开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
介绍
线程到底有几种状态?
网上主要分为两种说法:
五种状态
- 新建状态(New)
- 就绪状态(Runnable)
- 运行状态(Running)
- 阻塞状态(Blocked)
- 死亡状态(Dead)
或
六种状态
- New(新创建)
- Runnable(可运行)
- Blocked(被阻塞)
- Waiting(无限期等待)
- Time waiting(限期等待)
- Terminated(已终止)
那么,到底哪种方法是对的,或者说更加权威。我们翻开源码看看线程到底有哪几种状态。
可以看到,源码里Thread类中还有个State枚举类表示线程的状态。总共有New、Runnable、Blocked、Waiting、Time waiting、Terminated六种状态。
接下来,我们就详细聊一下这六种状态。
新建状态
当我们创建一个线程时,这个线程就是处于新建状态。
Thread thread = new Thread(() -> {
System.out.println("线程开始执行");
});
可运行状态
当线程调用start方法的时候,线程就会处于可运行状态
thread.start();
其实可运行状态包含两部分
- 可运行状态
- 运行状态
当线程调用了start(),此时线程是处于可运行状态,但不一定是运行状态;只有当CPU时间片真正被线程占用,执行线程的run方法,线程才会变成运行状态。
被堵塞状态
线程无法获取对象锁时的状态。也就是说此时线程可能还是占用这CPU时间片,但是由于对象锁,线程无法往下执行,堵塞在了这里。
有两个线程thread1,thread2。
- thread1和thread2都会去执行testBlocked方法
- 但是testBlocked有对象锁
- 如果当thread1先获取到锁,那么thread2执行堵塞住,等待thread1执行完释放锁
- 但thread2可能还是拥有CPU时间片的,它只是在等待锁的释放而已。
public static void main(String[] args) {
Thread thread1 = new Thread(ThreadTest::testBlocked);
Thread thread2 = new Thread(ThreadTest::testBlocked);
thread1.start();
thread2.start();
}
public static synchronized void testBlocked(){
System.out.println(Thread.currentThread().getName() + "执行了。。。");
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
无限期等待状态
线程进入了等待CPU时间片的阶段,并且是没有时间限制的。
thread.wait();
执行线程的wait方法时,线程会释放CPU资源;只有当其他线程调用notify/notifyAll时,这个线程才会被唤醒,继续参与到CPU资源的争夺。
Thread t1 = new Thread(() -> System.out.println("1"));
Thread t2 = new Thread(() -> {
try {
t1.join();
System.out.println("2");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
执行线程t1的join方法时,t2线程会进入等待状态,直到t1线程执行完成,否则t2线程会一直等待下去。
限期等待状态
线程进入了等待CPU时间片的阶段,但是有时间限制的,当达到了限期时间,线程会继续加入到CPU时间片的争夺。
Thread.sleep(5000L);
执行sleep方法后,线程会释放CPU进入等待状态,直到达到了过期时间。
Thread t1 = new Thread(() -> System.out.println("1"));
Thread t2 = new Thread(() -> {
try {
t1.join(1000L);
System.out.println("2");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
执行线程t1的join方法时,t2线程会进入等待状态,直到t1线程执行完成,或者等到达到了过期时间,才会结束等待状态
终止状态
有三种方式都会导致线程的终止状态
- 线程任务正常结束
- 线程任务异常结束
- 调用stop方法停用线程
线程正常结束
线程的run方法正常执行完成,线程就会变为终止状态
线程异常结束
线程内部程序执行报错
程序报错,导致线程异常终止
Thread thread3 = new Thread(() -> System.out.println(1 / 0));
thread3.start();
堵塞/等待状态的线程执行interrupt()方法
由于调用了sleep方法,线程进入了等待状态。此时,调用interrupt()方法会导致报错,抛出InterruptedException异常,线程异常终止
Thread thread = new Thread(ThreadTest::testBlocked);
thread.start();
thread.interrupt();
public static synchronized void testBlocked(){
System.out.println(Thread.currentThread().getName() + "执行了。。。");
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
调用stop方法停用线程
stop方法是用来强行终止线程,它会释放子线程所持有的的所有锁,会导致共享数据的不一致性,是一种很危险的方式,所以不推荐使用。
最后简单画个图总结下
文中如有不足之处,欢迎指正!一起交流,一起学习,一起成长 ^v^