Java并发03:Java线程的生命周期 - 6种状态详解

引言:一次生产事故的排查 凌晨2点,生产环境告警:CPU使用率持续100%。 # 使用top命令查看,发现Java进程CPU占用异常 $ top PID USER %CPU %MEM COMMAND 12345 app 850.0 45.2 java -jar app.jar ← 8核CPU,占用850% 使用 jstack 查看线程状态: $ jstack 12345 > thread-dump.txt # 查看线程dump "http-nio-8080-exec-45" #78 daemon prio=5 os_prio=0 tid=0x00007f8c4c001000 nid=0x1a2b RUNNABLE java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) ... "DB-Pool-Worker-23" #56 daemon prio=5 os_prio=0 tid=0x00007f8c48005000 nid=0x1a1f WAITING java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) ... "Task-Executor-8" #45 daemon prio=5 os_prio=0 tid=0x00007f8c44003000 nid=0x1a0d BLOCKED java.lang.Thread.State: BLOCKED (on object monitor) at com.example.Service.process(Service.java:42) - waiting to lock <0x000000076b5d4c00> (a java.lang.Object) ... RUNNABLE、WAITING、BLOCKED… 这些状态是什么意思? ...

2025-11-20 · maneng

死锁的产生与排查:从原理到实战

一、什么是死锁? 1.1 死锁示例 public class DeadlockDemo { private static Object lock1 = new Object(); private static Object lock2 = new Object(); public static void main(String[] args) { // 线程1:先锁lock1,再锁lock2 Thread t1 = new Thread(() -> { synchronized (lock1) { System.out.println("线程1:持有lock1,等待lock2"); sleep(100); // 模拟业务逻辑 synchronized (lock2) { System.out.println("线程1:获取lock2成功"); } } }); // 线程2:先锁lock2,再锁lock1 Thread t2 = new Thread(() -> { synchronized (lock2) { System.out.println("线程2:持有lock2,等待lock1"); sleep(100); synchronized (lock1) { System.out.println("线程2:获取lock1成功"); } } }); t1.start(); t2.start(); // 输出: // 线程1:持有lock1,等待lock2 // 线程2:持有lock2,等待lock1 // ... 程序卡住,发生死锁! } private static void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } } 死锁定义: 两个或多个线程互相持有对方需要的资源,导致所有线程都无法继续执行。 ...

2025-11-20 · maneng

Java并发02:进程与线程的本质 - 操作系统视角

引言:Chrome的选择 打开Chrome浏览器的任务管理器(Shift + Esc),你会看到: 任务管理器 ┌──────────────────────┬────────┬────────┐ │ 任务 │ 内存 │ CPU │ ├──────────────────────┼────────┼────────┤ │ 浏览器进程 │ 80 MB │ 1% │ │ GPU进程 │ 120 MB │ 2% │ │ 标签页: 百度 │ 65 MB │ 0% │ │ 标签页: GitHub │ 95 MB │ 3% │ │ 标签页: YouTube │ 150 MB │ 15% │ │ 扩展程序: AdBlock │ 25 MB │ 0% │ └──────────────────────┴────────┴────────┘ 为什么Chrome选择多进程架构,而不是多线程? 如果用多线程,YouTube标签页崩溃 → 整个浏览器崩溃 如果用多进程,YouTube标签页崩溃 → 只影响一个标签页 这背后涉及进程与线程的本质区别。 ...

2025-11-20 · maneng

并发设计模式:经典模式与最佳实践

一、生产者-消费者模式 1.1 核心思想 生产者线程 → [队列] → 消费者线程 - 生产者:生产数据,放入队列 - 消费者:从队列取出数据,处理 - 队列:解耦生产者和消费者 优势: ✅ 解耦:生产者和消费者独立 ✅ 削峰填谷:队列缓冲,应对突发流量 ✅ 异步处理:提高响应速度 1.2 BlockingQueue实现 public class ProducerConsumerDemo { private BlockingQueue<Task> queue = new LinkedBlockingQueue<>(100); // 生产者 class Producer implements Runnable { @Override public void run() { while (true) { try { Task task = produceTask(); queue.put(task); // 队列满时阻塞 System.out.println("生产:" + task); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } private Task produceTask() { // 生产任务 return new Task(); } } // 消费者 class Consumer implements Runnable { @Override public void run() { while (true) { try { Task task = queue.take(); // 队列空时阻塞 processTask(task); System.out.println("消费:" + task); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } private void processTask(Task task) { // 处理任务 } } public static void main(String[] args) { ProducerConsumerDemo demo = new ProducerConsumerDemo(); // 启动3个生产者 for (int i = 0; i < 3; i++) { new Thread(demo.new Producer()).start(); } // 启动5个消费者 for (int i = 0; i < 5; i++) { new Thread(demo.new Consumer()).start(); } } } 二、线程池模式 2.1 核心思想 任务提交 → [线程池] → 线程执行 - 预创建线程,复用线程资源 - 避免频繁创建/销毁线程的开销 - 控制并发数量,避免资源耗尽 2.2 自定义线程池 public class CustomThreadPool { private final BlockingQueue<Runnable> taskQueue; private final List<WorkerThread> workers; private volatile boolean isShutdown = false; public CustomThreadPool(int poolSize, int queueSize) { taskQueue = new LinkedBlockingQueue<>(queueSize); workers = new ArrayList<>(poolSize); // 创建工作线程 for (int i = 0; i < poolSize; i++) { WorkerThread worker = new WorkerThread(); workers.add(worker); worker.start(); } } // 提交任务 public void submit(Runnable task) { if (isShutdown) { throw new IllegalStateException("线程池已关闭"); } try { taskQueue.put(task); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } // 关闭线程池 public void shutdown() { isShutdown = true; for (WorkerThread worker : workers) { worker.interrupt(); } } // 工作线程 private class WorkerThread extends Thread { @Override public void run() { while (!isShutdown) { try { Runnable task = taskQueue.take(); task.run(); } catch (InterruptedException e) { break; } } } } } 三、Future模式 3.1 核心思想 主线程提交任务 → 异步执行 → 主线程继续工作 → 需要时获取结果 - 异步获取结果 - 主线程不阻塞 - 提高并发性能 3.2 简化实现 public class FutureDemo { // 自定义Future class FutureResult<T> { private volatile T result; private volatile boolean isDone = false; public void set(T result) { this.result = result; this.isDone = true; synchronized (this) { notifyAll(); // 唤醒等待线程 } } public T get() throws InterruptedException { if (!isDone) { synchronized (this) { while (!isDone) { wait(); // 等待结果 } } } return result; } } // 异步任务 public FutureResult<String> asyncTask() { FutureResult<String> future = new FutureResult<>(); new Thread(() -> { // 模拟耗时操作 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } // 设置结果 future.set("异步任务完成"); }).start(); return future; // 立即返回Future } public static void main(String[] args) throws InterruptedException { FutureDemo demo = new FutureDemo(); // 提交异步任务 FutureResult<String> future = demo.asyncTask(); // 主线程继续工作 System.out.println("主线程继续工作..."); // 需要时获取结果 String result = future.get(); System.out.println("结果:" + result); } } 四、不变模式(Immutable Pattern) 4.1 核心思想 对象创建后,状态不可改变 - 无需同步:线程安全 - 简化并发:无竞态条件 - 高性能:无锁开销 4.2 实现方式 // 不变对象 public final class ImmutablePoint { private final int x; private final int y; public ImmutablePoint(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } // 修改操作返回新对象 public ImmutablePoint move(int deltaX, int deltaY) { return new ImmutablePoint(x + deltaX, y + deltaY); } } // 使用 ImmutablePoint p1 = new ImmutablePoint(0, 0); ImmutablePoint p2 = p1.move(10, 10); // 新对象 // 多线程安全:p1和p2都不会被修改 关键要素: ...

2025-11-20 · maneng

Java并发01:为什么需要并发编程 - 从单线程到多线程的演进

引言:一个Web服务器的故事 假设你正在开发一个简单的Web服务器,用户访问网站时,服务器需要处理请求并返回响应。最初,你可能会写出这样的代码: public class SimpleWebServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8080); System.out.println("服务器启动,监听端口 8080..."); while (true) { // 接受客户端连接 Socket client = serverSocket.accept(); // 处理请求(耗时操作) handleRequest(client); // 关闭连接 client.close(); } } private static void handleRequest(Socket client) throws IOException { // 读取请求 BufferedReader in = new BufferedReader( new InputStreamReader(client.getInputStream())); String request = in.readLine(); // 模拟业务处理:查询数据库、调用外部API等(耗时500ms) try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } // 返回响应 PrintWriter out = new PrintWriter(client.getOutputStream(), true); out.println("HTTP/1.1 200 OK"); out.println("Content-Type: text/plain"); out.println(); out.println("Hello, World!"); } } 问题来了: ...

2025-11-20 · maneng

StampedLock性能优化:比读写锁更快的乐观读锁

一、ReadWriteLock的性能瓶颈 1.1 读写锁的问题 // ReadWriteLock:读多写少场景的优化 ReadWriteLock rwLock = new ReentrantReadWriteLock(); // 读操作 rwLock.readLock().lock(); try { // 读取数据 return data; } finally { rwLock.readLock().unlock(); } // 写操作 rwLock.writeLock().lock(); try { // 修改数据 data = newData; } finally { rwLock.writeLock().unlock(); } 性能瓶颈: 读锁也是锁:虽然允许多个读线程并发,但获取/释放锁仍有开销 CAS竞争:多个读线程获取读锁时,仍需CAS操作state变量 写锁饥饿:大量读操作时,写操作可能长时间等待 1.2 StampedLock的突破 StampedLock sl = new StampedLock(); // 乐观读(无锁) long stamp = sl.tryOptimisticRead(); // 获取戳记(无锁) int value = data; // 读取数据 if (sl.validate(stamp)) { // 验证戳记是否有效 return value; // 有效,直接返回 } // 无效:升级为悲观读锁 stamp = sl.readLock(); try { return data; } finally { sl.unlockRead(stamp); } 核心优势: ...

2025-11-20 · maneng

无锁编程与LongAdder:高并发计数器的性能优化

一、AtomicLong的性能瓶颈 1.1 高并发下的问题 // 1000个线程,每个线程累加100万次 AtomicLong counter = new AtomicLong(0); ExecutorService executor = Executors.newFixedThreadPool(1000); for (int i = 0; i < 1000; i++) { executor.submit(() -> { for (int j = 0; j < 1_000_000; j++) { counter.incrementAndGet(); // CAS操作 } }); } // 耗时:约 15秒(高并发场景) 性能瓶颈: CAS自旋:高并发时,CAS失败率高,大量自旋消耗CPU 缓存失效:所有线程竞争同一个变量,导致CPU缓存频繁失效(Cache Line伪共享) 串行化:本质上是串行执行,无法充分利用多核CPU 1.2 LongAdder的解决方案 // 同样的场景,使用LongAdder LongAdder counter = new LongAdder(); ExecutorService executor = Executors.newFixedThreadPool(1000); for (int i = 0; i < 1000; i++) { executor.submit(() -> { for (int j = 0; j < 1_000_000; j++) { counter.increment(); // 分段累加 } }); } long result = counter.sum(); // 最终求和 // 耗时:约 2秒(高并发场景) // 性能提升:约 7.5倍! 为什么更快? ...

2025-11-19 · maneng

ForkJoinPool与工作窃取算法:高性能并行计算的秘密

一、为什么需要ForkJoinPool? 1.1 传统线程池的局限 // 传统线程池处理递归任务 ExecutorService executor = Executors.newFixedThreadPool(4); // 计算斐波那契数列(递归) public int fib(int n) { if (n <= 1) return n; // 提交子任务 Future<Integer> f1 = executor.submit(() -> fib(n - 1)); Future<Integer> f2 = executor.submit(() -> fib(n - 2)); // 等待子任务完成 return f1.get() + f2.get(); // ❌ 可能导致线程池死锁! } 问题: 线程池死锁:父任务等待子任务,但子任务在队列中等待线程,形成死锁 负载不均:某些线程任务多,某些线程空闲,资源利用率低 任务粒度:传统线程池适合粗粒度任务,不适合细粒度递归任务 1.2 ForkJoinPool的解决方案 // ForkJoinPool 专为递归任务设计 ForkJoinPool pool = new ForkJoinPool(); class FibTask extends RecursiveTask<Integer> { private int n; protected Integer compute() { if (n <= 1) return n; // 分解子任务 FibTask f1 = new FibTask(n - 1); FibTask f2 = new FibTask(n - 2); // 异步执行左子任务 f1.fork(); // 同步执行右子任务,并等待左子任务 return f2.compute() + f1.join(); // ✅ 不会死锁 } } int result = pool.invoke(new FibTask(10)); 核心优势: ...

2025-11-19 · maneng

CompletableFuture实战:异步编程最佳实践

一、为什么需要CompletableFuture? 1.1 传统Future的局限 // Future的问题 ExecutorService executor = Executors.newFixedThreadPool(10); Future<String> future = executor.submit(() -> { Thread.sleep(1000); return "result"; }); // ❌ 只能阻塞等待 String result = future.get(); // 阻塞! // ❌ 无法组合多个异步任务 // ❌ 无法处理异常回调 // ❌ 无法设置超时后的默认值 1.2 CompletableFuture的优势 // ✅ 链式编程 CompletableFuture.supplyAsync(() -> "Hello") .thenApply(s -> s + " World") .thenAccept(System.out::println); // ✅ 任务组合 CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "A"); CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "B"); CompletableFuture<String> result = future1.thenCombine(future2, (a, b) -> a + b); // ✅ 异常处理 CompletableFuture.supplyAsync(() -> { if (Math.random() > 0.5) throw new RuntimeException("Error"); return "OK"; }).exceptionally(ex -> "Default"); 核心改进: ...

2025-11-19 · maneng

如约数科科技工作室

浙ICP备2025203501号

👀 本站总访问量 ...| 👤 访客数 ...| 📅 今日访问 ...