Java 中线程通信方式笔记
目录
- 线程通信的定义
- 使用
wait()
/notify()
通信 - 使用
join()
实现线程串行 - 使用
volatile
实现可见性通信 - 使用
LockSupport
- 使用
Condition
- 使用
BlockingQueue
- 使用
CountDownLatch
、CyclicBarrier
、Semaphore
- 使用
Future
/CompletableFuture
- 总结
1.线程通信的定义
线程通信是指多个线程在协同完成某个任务时,为了数据同步或协作调度而相互传递信息或等待状态变化的机制。
常见目的:
- 数据共享同步(生产者-消费者)
- 控制线程顺序(线程 A -> 线程 B)
- 等待某一条件满足后继续执行
2.使用 wait()
/ notify()
通信
最基础的通信方式,依赖对象锁和监视器机制。
示例:
class Shared {private boolean ready = false;public synchronized void waitForSignal() throws InterruptedException {while (!ready) {wait(); // 释放锁 + 阻塞}System.out.println("Signal received!");}public synchronized void sendSignal() {ready = true;notify(); // 唤醒等待线程}
}
特点:
- 必须配合
synchronized
使用 wait()
会释放锁,notify()
不会- 建议使用
while
判断条件防止虚假唤醒
3.使用 join()
实现线程串行
等待其他线程执行完成,适合线程之间有执行顺序依赖的场景。
示例:
Thread t1 = new Thread(() -> {System.out.println("T1 done");
});
Thread t2 = new Thread(() -> {try {t1.join();System.out.println("T2 done after T1");} catch (InterruptedException e) {}
});t1.start();
t2.start();
4.使用 volatile
实现可见性通信
适用于简单的标志状态共享,如线程停止。
示例:
class Flag {volatile boolean stop = false;
}Flag flag = new Flag();new Thread(() -> {while (!flag.stop) {// do work}
}).start();Thread.sleep(1000);
flag.stop = true;
特点:
- 保证线程间变量的可见性
- 不保证原子性
- 适合轻量级信号传递
5.使用 LockSupport
线程阻塞和唤醒的底层工具,替代 wait/notify
,无需加锁。
示例:
Thread t = new Thread(() -> {System.out.println("Thread park");LockSupport.park();System.out.println("Thread unparked");
});
t.start();Thread.sleep(1000);
LockSupport.unpark(t);
特点:
- 每个线程有一个许可证(类似信号量)
- 更灵活,不依赖同步锁
- 常用于实现框架级线程调度
6.使用 Condition
是 Lock
的增强版 wait/notify
,支持多个条件队列。
示例:
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();Thread t1 = new Thread(() -> {lock.lock();try {condition.await(); // 类似 wait()System.out.println("Thread t1 resumed");} catch (InterruptedException e) {} finally {lock.unlock();}
});Thread t2 = new Thread(() -> {lock.lock();condition.signal(); // 类似 notify()lock.unlock();
});
特点:
- 可精准唤醒特定条件队列中的线程
- 支持多个等待队列
7.使用 BlockingQueue
适合生产者-消费者模式,线程安全队列内置通信机制。
示例:
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);new Thread(() -> {try {queue.put(1); // 阻塞直到有空间} catch (InterruptedException e) {}
}).start();new Thread(() -> {try {Integer value = queue.take(); // 阻塞直到有元素System.out.println("Consumed: " + value);} catch (InterruptedException e) {}
}).start();
8.使用 CountDownLatch
/CyclicBarrier
/Semaphore
CountDownLatch
用于一个线程等待多个线程完成:
CountDownLatch latch = new CountDownLatch(2);new Thread(() -> {latch.countDown(); // 执行完毕
}).start();latch.await(); // 等待所有线程执行完
CyclicBarrier
适合多个线程在某个点同步:
CyclicBarrier barrier = new CyclicBarrier(3, () -> {System.out.println("All threads reached barrier");
});new Thread(() -> {barrier.await();
}).start();
Semaphore
用于控制线程数量(资源数):
Semaphore semaphore = new Semaphore(2); // 允许2个线程同时访问semaphore.acquire();
try {// 访问共享资源
} finally {semaphore.release();
}
9.使用 Future
/ CompletableFuture
线程间通过结果对象通信,适合异步执行与回调。
示例:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(() -> {return "result";
});String result = future.get(); // 阻塞直到任务完成
CompletableFuture
:
CompletableFuture.supplyAsync(() -> "Hello").thenApply(str -> str + " World").thenAccept(System.out::println);
总结
方式 | 适用场景 | 是否阻塞 | 特点 |
---|---|---|---|
wait/notify | 精细通信 | 是 | 必须配合锁 |
join | 等待线程完成 | 是 | 简单串行依赖 |
volatile | 状态通知 | 否 | 可见性但无原子性 |
LockSupport | 框架底层调度 | 是 | 灵活、无锁 |
Condition | 多条件控制 | 是 | 精细唤醒 |
BlockingQueue | 生产者消费者 | 是 | 内置通信机制 |
CountDownLatch | 等待一组线程 | 是 | 一次性门闩 |
CyclicBarrier | 多线程集结 | 是 | 可重复使用 |
Semaphore | 控制访问数量 | 是 | 控制并发度 |
Future/CompletableFuture | 异步编程 | 支持回调 | 返回值通信 |