天天看点

【图解】透彻Java线程状态转换

线程状态

先来个开场四连问

  • ​Java​

    ​线程状态有几个?
  • ​Java​

    ​线程状态是如何转换?
  • ​Java​

    ​线程状态转换什么情况会进入锁的等待队列?
  • ​Java​

    ​线程状态转换什么情况会进入锁的同步队列?

一提到​

​Java​

​​线程状态,不少读者立马想到线程状态转换图,但细想,印象又不深刻,只记得有那么几个状态。再要你说出​

​Java​

​线程状态是如何转换的,脑子里可能就如下图一样,已经是一团浆糊了。

【图解】透彻Java线程状态转换

别慌,阿星为了帮读者大大们理清楚上面的问题,会一步一步的把线程状态转换图给画出来,让读者大大们真正的理解Java线程状态转换。

首先线程的状态可以分为​

​6​

​态或​

​7​

​态,具体状态如下

6态

  • New

    :新建状态

  • Runnable

    :可运行状态

  • Terminated

    :终止状态

  • Waiting

    :等待状态

  • TimedWaiting

    :超时等待状态

  • Blocked

    :阻塞状态

7态

  • New

    :新建状态

  • Ready

    :就绪状态

  • Running

    :运行状态

  • Terminated

    :终止状态

  • Waiting

    :等待状态

  • TimedWaiting

    :超时等待状态

  • Blocked

    :阻塞状态

其实6态与7态差别不大,只不过​

​7​

​态把​

​Runnable​

​可运行状态,拆解成了​

​Ready​

​就绪状态与​

​Running​

​运行状态。阿星以​

​7​

​态为例,来逐步讲解它们之间是如何转换的。

新建状态(New)

我们可以通过实现​

​Runnable​

​接口或继承​

​Thread​

​声明一个线程类,​

​new​

​一个实例后,线程就进入了新建状态。

【图解】透彻Java线程状态转换
一个刚诞生的线程,处于新建状态。

就绪状态(Ready)

线程对象创建成功后,调用该线程的​

​start()​

​​函数,线程进入就绪状态,该状态的线程进入可运行线程池中,等待获取​

​C P U​

​的使用权。

【图解】透彻Java线程状态转换
线程表示,我已经准备好了,此时我是就绪状态,快选我吧~

运行状态(Running)

此时线程调度程序正在从可运行线程池中选择一个线程,该线程进入运行状态。

换句话说,线程获取到了​

​C P U​

​时间片。

【图解】透彻Java线程状态转换

还没完呢,当线程时间片用完或调用的​​

​yield()​

​​函数,该线程回到就绪状态。

【图解】透彻Java线程状态转换
作为一名运气好的线程,我进入了运行状态,但是运气用完了,我还得回到就绪状态。

终止状态(Terminated)

线程继续运行,直到执行结束或执行过程中因异常意外终止都会使线程进入终止状态。

线程一旦终止,就不能复生,这是不可逆的过程。

【图解】透彻Java线程状态转换
线程的人生迎来了终点,可能一帆风顺过完一生,也可能英年早逝令人惋惜。

等待状态(Waiting)

运行状态的线程执行wait()、join()、LockSupport.park()任意函数,该线程进入等待状态。

其中​

​wait()​

​与​

​join()​

​函数会让J V M把该线程放入锁等待队列。

处于这种状态的线程不会被分配C P U执行时间,它们要等待被主动唤醒,否则会一直处于等待状态。

【图解】透彻Java线程状态转换

如果我们要唤醒线程怎么办呢?

执行​

​LockSupport.unpark(t)​

​​函数唤醒指定线程,该线程回到就绪状态。而通过​

​notify()、notifyAll()、join线程执行完毕​

​方式,会唤醒锁等待队列的线程,出队的线程回到就绪状态。

【图解】透彻Java线程状态转换
线程的人生迎来了劫难,听信小人之言,跑去菲律宾做打工,结果被黑工厂扣下,只希望警察叔叔能早日解救我出去。

超时等待状态(Timed waiting)

超时等待与等待状态一样,唯一的区别就是多了超时机制,不会一直等待被其他线程主动唤醒,而是到达指定时间后会自动唤醒。

以下函数会触发进入超时等待状态

  • wait(long)
  • join(long)
  • LockSupport.parkNanos(long)
  • LockSupport.parkUtil(long)
  • sleep(long)

其中​

​wait(long)、join(long)​

​函数会让J V M把线程放入锁等待队列。

【图解】透彻Java线程状态转换

后面的唤醒剧情就和等待状态如出一辙,就多了超时时间到了,自动唤醒的动作。

【图解】透彻Java线程状态转换
从菲律宾回国后的线程,也做起了违法的勾当,最终被警察抓捕,好在只判了5年,熬一熬就可以出来了。

阻塞状态(Blocked)

运行状态的线程获取同步锁失败或发出​

​I/O​

​请求,该线程进入阻塞状态。如果是获取同步锁失败​

​J V M​

​还会把该线程放入锁的同步队列。

【图解】透彻Java线程状态转换

同步锁被释放时,锁的同步队列会出队所有线程,进入就绪状态。

​I/O​

​处理完毕时,该线程重新回到就绪状态。

【图解】透彻Java线程状态转换

小结

继续阅读