Java 多线程编程入门:线程创建、生命周期与基本控制
获课:bcwit.top/14205/
获取ZY↑↑方打开链接↑↑
一、线程创建:三种核心方式及其本质
- 继承 Thread 类
- 本质:重写 run() 定义任务逻辑,通过 start() 触发线程执行。
- 局限:单继承机制限制了扩展性,不符合组合优于继承的原则。
- 实现 Runnable 接口
- 本质:将任务与线程解耦,任务逻辑写在 run() 中,由 Thread 实例代理执行。
- 优势:支持多接口实现,任务可被多个线程共享,规避资源竞争风险。
- 实现 Callable + Future 模式
- 本质:通过 call() 方法返回结果,支持异常抛出,由线程池或 FutureTask 管理异步执行。
- 场景:需要获取线程执行结果或处理执行异常时使用。
核心差异:
Runnable/Callable 是任务定义,Thread 是执行载体;
Callable 是 Runnable 的升级版,支持返回值与异常。
二、线程生命周期:6种状态流转与触发条件
新建 NEW
可运行 RUNNABLE
阻塞 BLOCKED
等待 WAITING
限时等待 TIMED_WAITING
终止 TERMINATED
- NEW:new Thread() 后,未调用 start()。
- RUNNABLE:调用 start() 后,线程等待CPU调度(包含操作系统层面的 Running 和 Ready 状态)。
- BLOCKED:
- 触发条件:竞争 synchronized 锁失败,进入锁等待队列。
- WAITING:
- 触发条件:调用 object.wait()、thread.join() 或 LockSupport.park()。
- 唤醒方式:notify()/notifyAll() 或目标线程终止。
- TIMED_WAITING:
- 触发条件:调用 Thread.sleep(long)、object.wait(timeout) 等带超时参数的方法。
- TERMINATED:run() 执行结束或抛出未捕获异常。
关键认知:
RUNNABLE 状态不保证线程正在运行,仅表示“就绪”或“运行中”;
阻塞/等待是 被动行为,由资源竞争或程序逻辑主动触发。
三、线程控制:4大核心手段
1. 线程调度干预
- Thread.yield():提示调度器让出CPU,但不释放锁,不保证其他线程立即执行。
- 线程优先级(1~10):
- 仅作为调度器参考,高优先级不保证优先执行(依赖OS实现)。
- 滥用可能导致低优先级线程饿死(Starvation)。
2. 线程协作:join()机制
- 作用:强制调用线程等待目标线程终止(如:主线程等待子线程计算完毕)。
- 原理:底层通过 wait() 实现,当目标线程结束时触发 notifyAll()。
3. 线程中断:interrupt()
- 本质:向线程发送中断请求信号(设置中断标志位),非强制终止。
- 响应逻辑:
- 若线程在 wait()/sleep() 中,抛出 InterruptedException 并清除中断标志;
- 若线程在运行中,需通过 Thread.interrupted() 检测标志并主动终止。
- 正确用法:任务逻辑中循环检查中断状态,实现优雅退出。
4. 守护线程(Daemon Thread)
- 特性:当所有非守护线程结束时,JVM自动终止所有守护线程(如垃圾回收线程)。
- 使用场景:执行辅助性任务(监控、心跳检测等),不可用于资源操作(可能被强制中断导致数据不一致)。
四、新手常见误区
- 混淆 run() 和 start():
- 直接调用 run() 是同步方法执行,不会启动新线程。
- 误用线程控制手段:
- stop()/suspend()/resume() 已废弃,因其会导致资源未释放或死锁。
- 忽视线程中断的协作性:
- 中断请求需被任务逻辑响应,否则无效。
- 守护线程的资源风险:
- 守护线程中执行文件写入或DB操作,可能因JVM退出导致数据丢失。
五、设计思想:多线程的本质价值
- 核心目标:
- 响应性:避免主线程阻塞(如UI线程);
- 吞吐量:利用多核CPU并行计算。
- 平衡原则:
- 线程数并非越多越好(上下文切换开销);
- 任务拆分粒度影响并行效率(Amdahl定律)。