Java runnable停止线程_线程有多少种状态?Runnable 一定在执行任务吗?

线程有哪 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 种状态。然而,它是如何切换的呢?狗哥根据自己的理解做了一张图,接下来将根据这张图详细了解下线程状态的切换。

线程的 6 种状态

NEW (新创建)

先注意 NEW 状态:线程被 NEW 出来,但还没调用 start 方法时,就处于这种状态。一旦调用了 start 方法也就进入了 RUNNABLE 状态。

RUNNABLE(可运行)

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

因此,我们可以推断出,一个处于 Runnable 状态的线程,当它运行到任务的一半时,执行该线程的 CPU 被调度去做其他事情,则该线程暂时不运行。但是,它的状态依然不变,还是 Runnable,因为它有可能随时被调度回来继续执行任务。

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

Blocked(被阻塞)

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

线程的 6 种状态

再来,看图的右侧,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 ()。

线程的 6 种状态

看 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) 方法。

线程的 6 种状态

看 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 状态,只有处于中间状态才可以相互转换。

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页