目录
- NEW(新建状态) 新创建了一个线程对象,但是还没有调用start()方法
- RUNNABLE(运行态) Java线程中将就绪(READY)和运行中(RUNNING)两种状态并称为运行态,其一个线程被创建了,并且调用了这个线程对象的start()方法,这个线程对象就处于可运行的线程池中,等待被调度选中,获得CPU的使用权,这种状态称为就绪态(万事俱备,只差CPU),当这个线程获得了CPU的使用权,那么就会从就绪态变为运行中
- 阻塞(BLOCKED)表示这个线程阻塞于锁
- 等待(WAITING)进入这种状态的线程需要等待其他线程做出一些特定的动作(通知或者中断)
- 超时等待(TIME_WAITING)该状态不同于WAITINGM,它是指定的时间后自行返回
- 终止(TERMINATED) 表示该线程已经执行完毕
线程状态转换图
初始状态
关于NEW,我们通过实现Runnable接口或者继承Thread可以得到一个线程类,new出一个线程对象出来,这个线程就处于NEW状态
就绪状态(RUNNABLE之READY)
- 就绪(READY)和运行中(RUNNING)在就绪只是说明你有资格运行,只有系统调度你去运行你才是真正的RUNNING,否则你永远是READR
- 处于NEW态的线程调用start()就进入就绪状态
- 当一个线程sleep()方法结束,其他线程join结束,某个线程拿到了对象锁,这些线程也就进入了就绪状态
- 当前线程时间片用完,或者调用当前运行线程的yield()方法,当前线程进入就绪状态
- 锁池里的线程拿到对象锁之后,进行就绪状态
运行中状态(RUNNABLE之RUNNING)
- 线程的调度程序从可运行池中(RUNNING和READY)挑选一个线程作为运行线程,这是线程变为运行状态的唯一一种方式
yield方法
package thread; public class ThreadYield { public static void main(String[] args) { Thread t1 = new Thread(() -> { while (true) { System.out.println(Thread.currentThread().getName()); // 帅哥线程就会让出CPU,进入就绪态,等待被CPU继续调度 Thread.yield(); } },"帅哥线程"); t1.start(); Thread t2 = new Thread(() -> { while (true) { System.out.println(Thread.currentThread().getName()); } },"美女线程"); t2.start(); } }
- 我们发现帅哥线程执行yield,让出CPU的使用权,帅哥线程只是让出CPU,但是下此调度什么线程,还是由我们的操作系统说的算,可能下次调用的还是帅哥线程(只不过是我们执行完输出这个语句,就把CPU让出去了),也有可能是美女线程,我们无法干涉,只是每次执行到帅哥线程,都会把CPU让出去,让美女线程执行的次数可能较多一点
阻塞状态(BLOCKED)
- 阻塞状态就是线程阻塞在进入synchronized关键字修饰的方法或者代码块
等待(WAITING)
- 处于这种状态的线程不会被分配CPU执行时间,它们要等待被显式地唤醒,否则会处于无限期等待的状态。
超时等待(TIMED_WAITING)
- 处于这种状态的线程不会被分配CPU执行时间,不过无须无限期等待被其他线程显示地唤醒,在达到一定时间后它们会自动唤醒。
理解三大等待状态
package thread; public class ThreadBlocked { public static void main(String[] args) { Object lock=new Object(); Thread t1=new Thread(new Runnable() { @Override public void run() { synchronized (lock){ while (true){ try { //TIMED_WAITING //时间到了,自动结束等待,这里是等待1秒 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } },"t1"); t1.start(); Thread t2=new Thread(new Runnable() { @Override public void run() { //t2想执行这个里面的代码,必须等待t1释放lock这个锁 //因为t1先获得这个资源,对其上锁 synchronized (lock){ System.out.println("呵呵 小垃圾"); } } },"t2"); t2.start(); } }
- 我们发现在t1在sleep后,处于TIMED_WAITING状态,意思就是t1等待一秒后在继续运行(这里的运行只是RUNNABLE),何时是真正的使用CPU由调度程序说的算
- 我们发现t2处于BLOCKED状态,是因为t1先进入了synchronized,获得了lock这个资源,相当于对这个资源上锁了,如果t2想执行synchronized里的代码,就必须等待t1释放这个资源(解锁)
package thread; public class ThreadBlocked { public static void main(String[] args) { Object lock=new Object(); Thread t1=new Thread(new Runnable() { @Override public void run() { synchronized (lock){ // while (true){ // try { Thread.sleep(1000); // lock.wait(); // } catch (InterruptedException e) { // e.printStackTrace(); // } // } try { // Thread.sleep(1000); lock.wait(); System.out.println("我被唤醒了"); } catch (InterruptedException e) { e.printStackTrace(); } } } },"t1"); t1.start(); Thread t2=new Thread(new Runnable() { @Override public void run() { synchronized (lock){ System.out.println("呵呵 小垃圾"); } } },"t2"); t2.start(); } }
- 我们发现t2程序正常的运行结束,但是t1陷入死等了,状态是wait,如果想让t1结束wait状态,我们必须需要别的线程进行lock资源的notify(),这需要我们后面细讲其中的原理,wait必须搭配synchronized
总结
其实这三种其本质都是等待,只是等待的原因不一样
终止状态(TERMINATED)
- 当线程的run()方法完成时,或者主线程的main()方法完成时,或者抛出异常不正常执行完毕,我们就认为它终止了。这个线程对象也许是活的,但是它已经不是一个单独执行的线程。线程一旦终止了,就不能复生。
- 在一个终止的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。