概述
Java中线程的状态(也可以理解为生命周期),主要有以下几种:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED 。
这些状态存在于Thread类中的一个枚举中如下:
1 | public enum State { |
具体状态
NEW
- JDK原生的注释说的是一个还没有开始(started)的线程, 也就是说当new了一个线程之后,并没有调用start方法的时候,线程的状态就是NEW。
RUNNABLE
- 这个状态代表线程处于一个可运行的状态,但是不一定会执行,因为要考虑cpu核心数等影响,直到CPU时间分片给到当前线程,才会真正的执行。
BLOCKED
- 阻塞状态,通常都是在等待获取某个监视器的锁的时候会处于当前状态。
- 已知:
- 等待synchronized获取监视器对象锁的时候,线程的状态为:BLOCKED (on object monitor)
- 线程从WAITING/TIMED_WAITING(object.wait()方法)状态唤醒后,因为需要重新获取synchronized监视器对象,会先进入BLOCKED状态,待获取了监视器对象锁后,变为RUNNABLE状态。
WAITING
- 等待状态,一般是由于调用了如下方法而进入等待状态:
- Object#wait()
- Thread#join()
- LockSupport#park()
- 线程进入WAITING状态后,等待其他线程调用对应的通知对象才会唤醒。比如:
- Object.notify()
- Object.notifyAll()
TIMED_WAITING
- 一样是等待状态,但是区别是带有一个超时时间,超过这个时间后,线程会被自动唤醒。以下几个方法会进入该状态:
- Thread.sleep(long)
- Object#wait(long)
- Thread#join(long)
- LockSupport#parkNanos(long)
- LockSupport#parkUntil(long)
TERMINATED
- 线程的终止状态,也就是当前线程已经执行完成。
状态转换
- 这个网上图片已经一大把了,有一张图看着简单明了,我就直接引用了:
关于释放资源方面
锁的释放
- 通过synchronized获取监视器对象锁之后,有如下几个方式会释放锁资源:
- 方法或者代码块正常执行完成
- 方法或者代码块抛出异常,代码终止执行
- 调用监视器对象的wait方法,会释放锁资源
- 补充:
- 调用Thread.sleep方法不会释放锁资源
CPU资源的释放
- Thread.sleep(),会释放CPU资源,但是不会释放锁。
- Thread.yield(),会尝试放弃CPU资源,但是不会释放锁。(可能放弃后又立即获取到)
- 还有suspend()方法,由于已经过时,不再解释。
其他
obj.notify/notifyAll区别
- notify会随机唤醒监视obj的一个线程,具体是哪个无法指定,由JVM确定。
- notifyAll会唤醒所有监视obj的线程,然后重新去竞争,只有一个可以获取到资源。
wait/sleep/yield区别
- sleep()方法会释放CPU资源但是不会释放锁资源。
- wait()方法会释放CPU资源和锁资源。
- yield()方法仅释放CPU执行权,锁仍然占用,线程会被放入就绪队列,会在短时间内再次执行。
虚假唤醒
- 就是在没有调用obj.notify/notifyAll的前提下,obj.wait被唤醒了。
- 等待线程即使没有收到正确的信号,也能够执行后续的操作,这就可能影响程序执行的正常逻辑。
- 为了防止假唤醒,保存信号的成员变量将在一个while循环里接受检查,而不是在if表达式里。
- 示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class Sign {
private final Object obj = new Object();
private boolean flag = false;
public void doWait() throws InterruptedException {
synchronized (obj) {
while (!flag) {
obj.wait();
}
flag = false;
}
}
public void doNotify() {
synchronized (obj) {
flag = true;
obj.notifyAll();
}
}
}
RUNNABLE状态
- Java中没有线程所谓的RUNNING和READY状态,这两个状态合并到一起,为RUNNABLE状态。
- 也就是说即使线程处于RUNNABLE状态,也不一定就正在执行,可能正在等待CPU时间分片。