java线程
线程
线程基础
Java 线程(Thread)是 Java 编程语言中实现多任务处理的基本单位,它是程序执行的最小独立路径。线程运行在 Java 虚拟机(JVM)中,允许程序并发执行多个操作。每个线程有自己的调用栈和程序计数器,但与同一进程内的其他线程共享堆内存和方法区。
- 做什么
- 实现并发执行,让程序同时处理多个任务。利用多核 CPU,提高程序响应性。
- 解决什么问题
- 单线程程序的响应延迟
- 多任务处理的低效性
- 复杂任务的耦合性
- 如何解决问题
- 并发:单核 CPU 上,线程通过时间分片交替执行,模拟“同时”运行。
- 并行:多核 CPU 上,线程分配到不同核心,真正同时运行。
线程的生命周期
- **线程的生命周期:指的是线程从创建(new Thread())到销毁(run() 方法执行完成或异常终止)的整个过程。
- 线程状态:是线程在生命周期中某一时刻的具体状态,Java 定义了六种状态(Thread.State):
NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED。
线程的状态
Java 的线程状态由Thread.State枚举定义,共有六种状态,这些状态贯穿于线程从创建到销毁的整个生命周期。
- NEW(新建状态)
- 线程对象已创建,但尚未调用 start() 方法。
- 此时线程还未与底层操作系统线程关联,仅在 JVM 中分配内存。
- Thread thread = new Thread(runnable);
- RUNNABLE
- 线程已调用 start() 方法,可以被调度执行。包括“就绪”和“运行”两种子状态
- 就绪(Ready):等待 CPU 分配时间片。
- 运行(Running):正在执行 run() 方法。
- 线程已分配操作系统资源(如独立的调用栈)
- thread.start();
- 线程已调用 start() 方法,可以被调度执行。包括“就绪”和“运行”两种子状态
- BLOCKED(阻塞状态)
- 线程因等待锁(如 synchronized 块或方法)而暂停执行。
- 线程无法运行,直到锁被释放。
- WAITING(等待状态)
- 线程因调用某些方法(如 wait()、join())进入无限期等待,需其他线程唤醒。
- 线程暂停运行,等待外部通知。
- object.wait(); 或 thread.join();
- TIMED_WAITING(定时等待状态)
- 线程因调用带有超时参数的方法(如 sleep()、wait(timeout))进入有限期等待。
- 线程会在超时后自动恢复,或被提前唤醒。
- Thread.sleep(1000); 或 object.wait(1000);
- TERMINATED(终止状态)
- 线程执行完成(run() 方法结束)或因异常终止。
- 线程生命周期结束,资源被回收。
- run() 方法正常返回或抛出未捕获异常。
状态之间的转换关系
1 | flowchart TD |
线程执行原理
- 线程的创建
new Thread()- 分配内存:JVM 在堆内存中创建
Thread对象,并初始化其成员变量。 - 设置线程属性:包括线程名称、优先级、是否为守护线程等。
- 未激活状态:此时线程处于
NEW状态,尚未与操作系统线程绑定。1
2
3
4
5
6+-----------------+
| Java 堆 |
+-----------------+
| Thread 对象 |
| (线程对象) |
+-----------------+
- 分配内存:JVM 在堆内存中创建
- 线程的启动
thread.start()- 在 Java 虚拟机栈中为线程分配独立的栈帧: 每个线程都有自己独立的虚拟机栈,用于存储局部变量、方法调用栈帧等信息。
- 创建操作系统原生线程:
start()方法会调用操作系统底层的线程创建方法,创建一个与 Java 线程对应的原生线程。 - 将线程状态设置为 RUNNABLE: 线程被创建后,初始状态为 NEW。调用
start()方法后,线程状态变为RUNNABLE,表示线程已经准备好运行,等待 CPU 调度。1
2
3
4
5
6+-----------------+ +-----------------+
| Java 堆 | | 虚拟机栈 (线程) |
+-----------------+ +-----------------+
| Thread 对象 | | 局部变量 |
| (线程对象) | | 方法调用栈帧 |
+-----------------+ +-----------------+
- 线程的运行
runnable.run()
操作系统调度到该线程时,线程开始执行Thread对象的run()方法。run()方法中包含了线程要执行的任务代码。- 同步机制:监视锁竞争(
synchronized)、wait/notify调用等。 - 状态迁移触发
- BLOCKED:竞争锁失败
- WAITING/TIMED_WAITING:调用
Object.wait()或Thread.sleep() - TERMINATED:
run()方法执行完成或抛出未捕获异常1
2
3
4
5
6
7
8+-----------------+ +-----------------+
| Java 堆 | | 虚拟机栈 (线程) |
+-----------------+ +-----------------+
| Thread 对象 | | 局部变量 |
| (线程对象) | | 方法调用栈帧 |
+-----------------+ +-----------------+
| | | run() 方法 | <-- run() 方法应该在栈顶
+-----------------+ +-----------------+
- 同步机制:监视锁竞争(
- 线程的结束
当线程执行完run()方法中的所有代码后,线程会正常结束。此时,线程状态变为TERMINATED。JVM 会回收线程的栈空间,并释放与线程相关的资源。1
2
3
4
5
6+-----------------+
| Java 堆 |
+-----------------+
| Thread 对象 |
| (线程对象) |
+-----------------+
示意图:线程生命周期与 JVM/OS 交互
1 | +----------------+ start() +-------------------+ |
1 | flowchart TD |
开启线程的方法
Thread
- 继承Thread类,重写Run方法
- 创建Thread实例,入参Runnable接口实现
继承Thread类
实现Runnable接口
实现Callable接口
线程池
Callable 与 Runnable的不同点
- Callable支持返回值,Runnable不行
- Callable可以抛出异常,Runnable不行
- Callable必须和线程池联合使用
- Runnable可在线程池和Thread类中使用
线程安全与同步机制
多个线程对同一数据(共享数据)进行读写操作,造成数据错乱
- 同步代码块 synchronized
- 同步方法 synchronized
- Lock锁
死锁
线程通讯
- 在A线程运行的过程中,可以唤醒其他处于”等待状态“的线程。
- 需要使用到
等待唤醒机制- 等待: wait()
- 唤醒: notify()、notifyAll()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public final static Object 对象锁= new Object();
同步代码块(对象锁){
对象锁.wait()
//...
对象锁.notify() //唤醒和当前对象锁绑定的其他处于等待状态的线程
}
//同步方法
非静态的同步方法() //对象锁 this
{
this.wait();
//..
this.notify();
}