thread
线程与并发基础
ToC
- 线程创建与状态
- 中断机制与守护线程
- 可见性与内存语义概览
- join/sleep/yield 区别
- 最佳实践
线程创建与状态
创建方式:
- 继承
Thread并重写run(); - 实现
Runnable; - 提交到线程池(推荐,统一管理线程)。
典型状态(Thread.State):NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。
常见导致阻塞/等待的原因:
synchronized进入监视器失败 →BLOCKEDObject.wait()→WAITINGLockSupport.parkNanos()/sleep()/join(timeout)→TIMED_WAITING
中断机制与守护线程
- 中断通过“标志位”协作完成:
thread.interrupt()设置中断标志;被阻塞方法(sleep/wait/join)会抛出InterruptedException并清除标志。 - 查询与响应:
Thread.interrupted()(静态,查询并清除);isInterrupted()(实例,查询不清除)。 - 守护线程(Daemon):随非守护线程全部结束而退出,适用于后台任务;不要依赖
finally做关键清理。
示例:
class Worker implements Runnable {
@Override public void run() {
while (!Thread.currentThread().isInterrupted()) {
// do work
try { Thread.sleep(10); } catch (InterruptedException e) {
// 恢复中断状态并退出循环
Thread.currentThread().interrupt();
}
}
}
}
可见性与内存语义概览
- 线程间通信依赖主内存,缓存/重排序可能导致“看不见”的写入。
synchronized与Lock的加解锁自带内存语义(建立 happens-before)。volatile保证可见性与一 定的有序性,但不保证复合操作的原子性。
详细规则与示例参见「Java 内存模型 JMM 与 volatile」。
join/sleep/yield 区别
sleep(ms): 让出 CPU 一段时间,不释放锁;时间到后进入可运行状态。yield(): 提示调度器让出时间片,效果不保证;不释放锁。join(): 当前线程等待目标线程结束,内部基于wait/notify实现。
最佳实践
- 尽量使用线程池统一管理线程的创建与销毁。
- 编写可响应中断的循环与阻塞逻辑;不要吞掉
InterruptedException。 - 对共享数据使用不可变对象、
final字段、volatile或显式同步。 - 使用高层并发工具(如
BlockingQueue、Semaphore、CountDownLatch、CompletableFuture)。
线程池与 CompletableFuture 示例
ExecutorService pool = Executors.newFixedThreadPool(8);
try {
Future<Integer> f = pool.submit(() -> 1 + 1);
System.out.println(f.get());
} finally {
pool.shutdown();
}
// CompletableFuture 并行组合
CompletableFuture<Integer> a = CompletableFuture.supplyAsync(() -> 1);
CompletableFuture<Integer> b = CompletableFuture.supplyAsync(() -> 2);
int sum = a.thenCombine(b, Integer::sum).join();