乐趣区

关于java:工作三年小胖居然问我线程有多少种状态真的菜

哈喽,大家好,我是狗哥。良久没有更新原创文章了。次要是因为往年上半年这段时间都在忙着经营我的小号:上路的狗哥 ,次要分享一些职场以及生存中的高效又乏味的工具, 比方:某度网盘提速工具、收费的 OCR 辨认工具、免费听全网音乐的 APP 以及收费看全网影视的 APP 等等,感兴趣的能够关注一下。

通过半年的经营,小号在齐全零推广的状况下累计了 1.3W 铁粉。为什么忽然又更新技术原创文章了?次要是因为写代码才是我的主业,公众号只是个人兴趣。做事不能轻重倒置,所以决定当前还是要周更这个技术公众号。

线程有哪 6 种状态?

人有生老病死。同样的,线程有本人的生命周期。在 Java 中线程的生命周期中一共有 6 种状态:

  • New(新创建)
  • Runnable(可运行)
  • Blocked(被阻塞)
  • Waiting(期待)
  • Timed Waiting(计时期待)
  • Terminated(被终止)

查看 Thread 类的源码时,外部还定义了这样一个枚举类。这个枚举类定义的就是线程的状态,源码如下:

public enum State {
       
        NEW,

        RUNNABLE,

        BLOCKED,

        WAITING,

        TIMED_WAITING,

        TERMINATED;
}

PS:线程在任何时刻只可能处于以上 6 种的其中 1 种状态 ,咱们 能够调用 getState() 查看线程的状态

线程是如何切换状态的?

咱们晓得线程有 6 种状态。然而,它是如何切换的呢?狗哥依据本人的了解做了一张图,接下来将依据这张图具体理解下线程状态的切换。

NEW(新创建)

先留神 NEW 状态:线程被 NEW 进去,但还没调用 start 办法时,就处于这种状态。一旦调用了 start 办法也就进入了 RUNNABLE 状态。

RUNNABLE(可运行)

处于 RUNNABLE 的线程,比拟非凡。它还分两种状态:Running 和 Ready。也就是说,Java 中处于 Runnable 状态的线程有可能正在执行,也有可能没有正在执行,正在期待被调配 CPU 资源

因而,咱们能够推断出,一个处于 Runnable 状态的线程,当它运行到工作的一半时,执行该线程的 CPU 被调度去做其余事件,则该线程临时不运行。然而,它的状态仍然不变,还是 Runnable,因为它有可能随时被调度回来继续执行工作

也就是说:处于 Runnable 状态的线程并不一定在运行。这点在面试中常问,小伙伴们要留神了。

Blocked(被阻塞)

再来看看最简略的 Blocked 状态,从 Runnable 进入 Blocked 只有一种可能:就是进入 synchronized 关键字爱护的代码,然而没有获取到 monitor 锁

再来,看图的右侧,Blocked —-> Runnable 状态:当处于 Blocked 状态的线程获取到锁

Waiting(期待)

线程从 Runnable 进入 Blocked 状态,有三种可能性:

  • 没有设置 Timeout 参数的 Object.wait () 办法。
  • 没有设置 Timeout 参数的 Thread.join () 办法。
  • LockSupport.park () 办法。

下面咱们晓得,线程进入 Blocked 状态只可能是:进入 synchronized 爱护的代码,然而没获取到 monitor 锁。然而,Java 中还有很多锁,比方:ReentrantLock。线程在获取这种锁时,没有抢到就会进入 Waiting 状态,因为它实质上是调用了 LockSupport.park () 办法。

同样的,调用 Object.wait () 和 Thread.join () 也会让线程进入期待状态

Blocked 与 Waiting 的区别是:Blocked 在期待其余线程开释 monitor 锁,而 Waiting 则是在期待某个条件,比方 join 的线程执行结束,或者是 notify ()/notifyAll ()

看 Waiting 右侧,Waiting —-> Runnable:1、当执行了 LockSupport.unpark (),2、join 的线程运行完结,3、被中断

看 Waiting 右侧,Waiting —-> Blocked:咱们看图能够晓得其余线程调用 notify () 或 notifyAll () 来唤醒处于 Waiting 的线程,它会间接进入 Blocked 状态。这是为什么?

其余线程能调用 notify () 或 notifyAll () 试图唤醒 Waiting 状态线程,阐明必须持有同一个 monitor 锁,也就是说 处于 Waiting 的线程被唤醒后并不能马上抢到 monitor 锁 ,所以它必须先进入 Blocked 状态。而 唤醒它的线程执行结束开释锁后,它能抢到锁就从 Blocked 进入 Runnable 状态

Timed Waiting(计时期待)

这种状态与 Waiting 状态的区别在于:有没有工夫限度,Timed Waiting 会期待超时,由零碎主动唤醒,或者在超时前被唤醒信号唤醒

有以下 5 种状况会让线程进入 Timed Waiting 状态:

  • 设置 Timeout 参数的 Thread.sleep (time) 办法。
  • 设置 Timeout 参数的 Object.wait (time) 办法。
  • 设置 Timeout 参数的 Thread.join (time) 办法。
  • 设置 Timeout 参数的 LockSupport.parkNanos (long nanos) 办法。
  • 设置 Timeout 参数的 LockSupport.parkUntil (long deadline) 办法。

看 Timed Waiting 右侧,Timed Waiting —-> Blocked:跟 Waiting 一样,其余线程执行 notify () 和 notifyAll (),以后线程也是先进入 Blocked 状态,而后视锁的获取状况再决定是否进入 Runnable 状态。

另外,Timed Waiting —-> Runnable:1、以后线程的超时工夫到了且能间接获取到锁,2、join 的线程运行完结,3、被中断,4、调用了 LockSupport.unpark (),这几种状况会间接复原到 Runnable,而无需经验 Blocked 状态。

Terminated(被终止)

最初一种,想要进入终止状态就比较简单了,有三种状况:

  • 工作执行结束,线程失常退出。
  • 呈现一个没有捕捉的异样(比方间接调用 interrupt() 办法)。

总结

  • 线程的状态是须要依照箭头方向走,比方线程从 New 状态是不能够间接进入 Blocked 状态的,它须要先经验 Runnable 状态。
  • 线程生命周期不可逆:一旦进入 Runnable 状态就不能回到 New 状态;一旦被终止就不可能再有任何状态的变动。所以一个线程只能有一次 New 和 Terminated 状态,只有处于中间状态才能够互相转换

伟人的肩膀

  • Java 并发编程 78 讲 — 徐隆曦

福利

如果看到这里,喜爱这篇文章的话,请帮点个难看。微信搜寻 一个优良的废人 ,关注后回复 电子书 送你 100+ 本编程电子书,不只 Java 哦,详情看下图。回复 1024送你一套残缺的 java 视频教程。

退出移动版