Java 线程全面概述
线程是程序执行的最小单元,是操作系统能够调度的最小单位。Java 提供了完善的线程支持,下面从基础概念到高级特性进行全面解析。
一、线程基础概念
1. 线程 vs 进程
特性 | 进程 | 线程 |
---|---|---|
资源占用 | 独立内存空间 | 共享进程内存 |
切换成本 | 高(上下文切换复杂) | 低 |
通信方式 | 管道、Socket、文件等 | 直接读写共享变量 |
健壮性 | 一个进程崩溃不影响其他 | 一个线程崩溃可能导致整个进程终止 |
2. Java 线程实现原理
- JVM 线程模型:1:1 映射到操作系统原生线程
- 线程生命周期:新建(NEW)→就绪(RUNNABLE)→运行(RUNNING)→阻塞(BLOCKED/WAITING)→终止(TERMINATED)
二、线程创建方式
1. 继承 Thread 类
class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程运行中");}
}// 使用
new MyThread().start();
2. 实现 Runnable 接口(推荐)
class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("实现Runnable的线程");}
}// 使用
new Thread(new MyRunnable()).start();
3. 实现 Callable 接口(带返回值)
class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "带返回值的线程";}
}// 使用
FutureTask<String> future = new FutureTask<>(new MyCallable());
new Thread(future).start();
System.out.println(future.get()); // 获取返回值
4. 线程池创建(最优方案)
ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(() -> {System.out.println("线程池任务");
});
executor.shutdown();
三、线程核心操作
1. 线程控制方法
方法 | 作用 | 备注 |
---|---|---|
start() | 启动线程 | 只能调用一次 |
sleep(long ms) | 线程休眠 | 不释放锁 |
yield() | 让出CPU时间片 | 建议不要依赖其行为 |
join() | 等待线程结束 | 常用于线程协调 |
interrupt() | 中断线程 | 需配合中断标志检查 |
2. 线程状态转换
四、线程同步机制
1. synchronized 关键字
// 同步方法
public synchronized void syncMethod() {// 临界区代码
}// 同步代码块
public void someMethod() {synchronized(this) {// 临界区代码}
}
2. Lock 接口
Lock lock = new ReentrantLock();
lock.lock();
try {// 临界区代码
} finally {lock.unlock();
}
3. 原子类(Atomic)
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet(); // 原子操作
4. 同步工具类
类 | 用途 |
---|---|
CountDownLatch | 等待多个线程完成 |
CyclicBarrier | 线程到达屏障时同步 |
Semaphore | 控制并发线程数 |
Exchanger | 线程间数据交换 |
五、线程通信方式
1. wait()/notify()
synchronized(lock) {while(conditionNotMet) {lock.wait(); // 释放锁并等待}// 处理逻辑lock.notifyAll(); // 唤醒其他线程
}
2. BlockingQueue
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
// 生产者
queue.put("data");
// 消费者
String data = queue.take();
3. Condition 条件变量
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();lock.lock();
try {condition.await(); // 类似wait()condition.signal(); // 类似notify()
} finally {lock.unlock();
}
六、线程安全设计原则
- 不可变对象:优先使用 final 字段
- 线程封闭:ThreadLocal 实现线程私有数据
- 减小同步范围:同步块尽可能小
- 使用并发容器:如
ConcurrentHashMap
- 避免死锁:按固定顺序获取多个锁
七、高级特性
1. ThreadLocal
ThreadLocal<String> threadLocal = ThreadLocal.withInitial(() -> "初始值");
threadLocal.set("线程私有数据");
String data = threadLocal.get();
2. Fork/Join 框架
class MyTask extends RecursiveTask<Integer> {@Overrideprotected Integer compute() {// 任务拆分与合并逻辑}
}ForkJoinPool pool = new ForkJoinPool();
pool.invoke(new MyTask());
3. CompletableFuture
CompletableFuture.supplyAsync(() -> "异步结果").thenApply(s -> s + "处理").thenAccept(System.out::println);
八、常见问题
1. 线程池参数如何配置?
- CPU密集型:核心线程数 = CPU核数 + 1
- IO密集型:核心线程数 = CPU核数 * 2
2. volatile 关键字作用?
- 保证变量可见性
- 禁止指令重排序(内存屏障)
3. 如何避免死锁?
- 按固定顺序获取锁
- 使用 tryLock() 设置超时
- 通过工具检测死锁(jstack)
九、性能优化建议
- 减少锁竞争:缩小同步范围,使用读写锁
- 合理使用线程池:避免无限制创建线程
- 避免上下文切换:控制线程数量
- 使用无锁算法:如 CAS 操作
掌握这些知识后,你将能够:
- 正确创建和管理线程
- 处理复杂的线程同步问题
- 设计高性能的并发程序
- 诊断和解决多线程问题
十、进程 vs 线程的生活化比喻
1. 比喻1:厨房做饭
- 进程:整个厨房(独立空间,有自己的灶台、冰箱、厨具)
- 线程:厨房里的不同厨师(共享厨房资源,但分工协作)
- 厨师A(线程1):切菜
- 厨师B(线程2):炒菜
- 厨师C(线程3):煮汤
对应概念:
- 资源竞争:如果两个厨师同时抢一把菜刀(共享资源),需要协调(同步)
- 协作问题:汤煮好后才能上菜(线程间通信)
2. 比喻2:快递公司
- 进程:一家快递公司(独立法人,有仓库、车辆、资金)
- 线程:公司的快递员(共享公司资源,各自送快递)
- 快递员A(线程1):配送海淀区包裹
- 快递员B(线程2):配送朝阳区包裹
对应概念:
- 资源共享:快递员共用公司卡车(内存共享)
- 独立工作:每个快递员有自己的配送路线(线程独立运行)
3. 比喻3:浏览器开网页
- 进程:一个浏览器窗口(独立内存,崩溃不影响其他窗口)
- 线程:窗口里的多个标签页(共享浏览器缓存、Cookie)
- 标签页1(线程1):播放视频
- 标签页2(线程2):下载文件
对应概念:
- 内存隔离:一个浏览器窗口崩溃不会影响其他窗口(进程独立性)
- 共享风险:如果浏览器缓存被恶意脚本修改,所有标签页受影响(线程共享资源的风险)
总结记忆表
概念 | 比喻 | 核心要点 |
---|---|---|
进程 | 独立厨房/快递公司 | 拥有独立资源,崩溃不影响其他 |
线程 | 厨师/快递员 | 共享资源,需协调,效率高但风险大 |
进程切换 | 换一家厨房做饭 | 成本高(要搬运所有厨具) |
线程切换 | 厨师换一道菜做 | 成本低(同一厨房内操作) |
进程间通信 | 两家公司发传真 | 速度慢,需要协议(IPC机制) |
线程间通信 | 厨师直接对话 | 速度快,但可能争吵(同步问题) |
多进程优势 | 开连锁店 | 稳定性高,适合隔离任务 |
多线程优势 | 餐厅多窗口点餐 | 资源利用率高,适合协作任务 |
记忆口诀
“进程像公司,独立有地盘,
线程是员工,共享又抱团,
切换公司成本高,内部换岗很轻便,
员工吵架要协调(同步),公司倒闭不牵连(隔离)!”