目录
- 线程通信的定义
- 使用
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 |
异步编程 | 支持回调 | 返回值通信 |