线程在执行过程中的状态是如何流转的?
1、线程的生命周期
下面是JDK源码:src/main/java/java/lang/Thread.java 中 线程状态State枚举 代码:
public enum State {
NEW, RUNNABLE, BLOCKED, WAITING,
TIMED_WAITING, TERMINATED;
}
2、线程的状态流转图
3、线程各个状态说明
3.1、NEW(初始化状态)
实现Runnable接口和继承Thread可以得到一个线程类,new一个实例出来,线程就进入了初始化状态。
方法一:继承Thread类
public class ThreadTest extends Thread{
public void run(){
for (int i = 1; i < 11; i++) {
System.out.println(Thread.currentThread().getName() + " thread " + i);
}
}
public static void main(String[] args) {
ThreadTest t1 = new ThreadTest();
t1.setName("thread1");
ThreadTest t2 = new ThreadTest();
t2.setName("thread2");
ThreadTest t3 = new ThreadTest();
t3.setName("thread3");
t1.start();
t2.start();
t3.start();
}
}
方法二:实现Runnable接口
public class TestRunnable implements Runnable{
@Override
public void run() {
for(int i=1;i<11;i++){
System.out.println(Thread.currentThread().getName()+" thread "+ i);
}
}
public static void main(String[] args) {
Thread t1=new Thread(new TestRunnable(),"thread1");
Thread t2=new Thread(new TestRunnable(),"thread2");
Thread t3=new Thread(new TestRunnable(),"thread3");
t1.start();
t2.start();
t3.start();
}
}
3.2、RUNNABLE(就绪,运行中状态)
READY 就绪
- 就绪状态只是说你自个儿运行,调度程序没有挑选到你,你就永远是就绪状态。
- 调用线程的start()方法,此线程进入就绪状态。
- 当前线程sleep()方法结束,其他线程join()结束,等待用户输入完毕,某个线程拿到对象锁,这些线程也将进入就绪状态。
- 当前线程时间片用完了,调用当前线程的yield()方法,当前线程进入就绪状态。
- 锁池里的线程拿到对象锁后,进入就绪状态。
3.3、RUNNING 运行中状态
线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。
3.4、BLOCKED(阻塞状态)
阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)之前时的状态。
3.5、WAITING(等待状态)
调用sleep或是wait方法后线程处于WAITING状态,等待被唤醒。
3.6、TIMED_WAITING(等待超时状态)
调用sleep或是wait方法后线程处于TIMED_WAITING状态,等待被唤醒或时间超时自动唤醒。
3.7、TERMINATED(终止状态)
-
当线程的run()方法完成时,或者主线程的main()方法完成时,我们就认为它终止了。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦终止了,就不能复生。
-
在一个终止的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。
4、线程状态之间的转换
4.1、NEW到RUNNABLE 状态
实现Runnable接口和继承Thread可以得到一个线程类,创建这个类的实例对象,就是NEW状态;
而NEW状态的线程是不会被操作系统调度,因此也不会被执行。所以,当这个线程要执行时,就必须调用这个对象的start()方法,将NEW 状态转换到 RUNNABLE 状态。
4.2、RUNNABLE与BLOCKED 的状态转换
目前只有当线程等待synchronized 的隐式锁时,线程才会从RUNNABLE 向BLOCKED 转换。
我们知道,被synchronized 关键字修饰的方法、代码块在同一时刻只允许一个线程执行,其他线程只能等待
所以,这种情况下,等待的线程就会从 RUNNABLE 转换到 BLOCKED 状态。而当等待的线程获得 synchronized 隐式锁时,就又会从 BLOCKED 转换到 RUNNABLE 状态。
4.3、RUNNABLE与WAITING 的状态转换
4.4、RUNNABLE与TIMED_WAITING 的状态转换
有5种场景会触发RUNNABLE向TIMED_WAITING转换:
- 调用带超时参数的 Thread.sleep(long millis) 方法;
- 获得 synchronized 隐式锁的线程,调用带超时参数的 Object.wait(long timeout) 方法;
- 调用带超时参数的 Thread.join(long millis) 方法;
- 调用带超时参数的 LockSupport.parkNanos(Object blocker, long deadline) 方法;
- 调用带超时参数的 LockSupport.parkUntil(long deadline) 方法。
- 这里你会发现 TIMED_WAITING 和 WAITING 状态的区别,仅仅是触发条件多了超时参数。
4.5、RUNNABLE到TERMINATED 状态
线程执行完 run() 方法后,会自动转换到 TERMINATED 状态,当然如果执行 run() 方法的时候异常抛出,也会导致线程终止。
如果需要强制中断 run() 方法的执行,则调用 interrupt() 方法。interrupt() 方法仅仅是通知线程,让线程有机会执行一些后续操作,同时也可以无视这个通知。
我们为了验证线程run()后,会自动转到terminated状态,所以,使用thread.getState()方法来获取“线程状态”。