Java的线程状态及其相互转换

线程的五个状态(生命周期)及其转换
Java创建线程的四种方式及其比较
Java线程常用方法详解

一、五个状态概述

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。

在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞 (Blocked)和死亡(Dead)5 种状态。尤其是当线程启动以后,它不可能一直"霸占"着 CPU 独自 运行,所以 CPU 需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换

1、初始状态(new)

实现Runnable、Callable接口或继承Thread可以得到一个线程类,new一个实例出来,线程就进入了初始状态

仅是在语言层面创建了线程对象,还未与操作系统线程关联

2、可运行状态(Runnable)

(就绪状态)指该线程已经被创建(与操作系统线程关联),可以由 CPU 调度执行 ,只是有资格运行,时间片没有轮到,就永远都是可运行状态

何时进入可运行状态:

  • 线程调用start()方法,可进入该状态;
  • 当前线程sleep()方法结束,可进入该状态;
  • 其他线程join()方法结束,等待用户输入完毕,某个线程拿到对象锁,这些线程也可进入该状态;
  • 当前线程时间片用完 了,调用当前线程的yield()方法,当前线程进入该状态;
  • 锁池里的线程拿到对象锁后,进入该状态。

3、运行状态(Running)

指获取了 CPU 时间片运行中的状态,这也是线程进入运行状态的唯一方式
当 CPU 时间片用完,会从【运行状态】转换至【可运行状态】,会导致线程的上下文切换

4、阻塞状态(Blocked)

如何进入阻塞状态:

  • 当前线程调用Thread.sleep()方法,当前线程进入该状态;
  • 运行在当前线程里的其他线程调用join()方法,当前线程进入该状态;
  • 等待用户输入的时候,当前线程进入该状态;

阻塞状态结束后进入可运行状态,等待调度

与【可运行状态】的区别是,对【阻塞状态】的线程来说只要它们一直不唤醒,调度器就一直不会考虑 调度它们

5、死亡状态(Dead)

表示线程已经执行完毕,生命周期已经结束,不会再转换为其它状态

有两个原因会导致线程死亡:

  • 当线程的run()方法完成时,或者主线程的main()方法完成时,我们就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。
  • 一个未捕获的异常终止了run方法而使线程猝死。

在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。

为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false.

二、线程状态之间的转换

以上的五种状态是从操作系统层面来描述的。

从Java API层面描述有六种状态:

  • NEW:即前一节所述的初始状态;
  • RUNNABLE:当调用了 start() 方法之后,注意,Java API 层面的 RUNNABLE 状态涵盖了 操作系统 层面的
    【可运行状态】、【运行状态】和【阻塞状态】(由于 BIO 导致的线程阻塞,在 Java 里无法区分,仍然认为 是可运行)
  • 阻塞状态:BLOCKED , WAITING , TIMED_WAITING 都是 Java API 层面对【阻塞状态】的细分
  • TERMINATED : 当线程代码运行结束
    Java的线程状态及其相互转换_第1张图片

1、NEW–>RUNNABLE

当调用 t.start() 方法时,由 NEW --> RUNNABLE

2 、RUNNABLE <–>WAITING

t 线程用 synchronized(obj) 获取了对象锁后

  • 调用 obj.wait() 方法时,t 线程从 RUNNABLE --> WAITING

  • 调用 obj.notify() , obj.notifyAll() , t.interrupt() 时

    1)竞争锁成功,t 线程从 WAITING --> RUNNABLE

    2)竞争锁失败,t 线程从 WAITING --> BLOCKED

例:

 public class TestWaitNotify {
    final static Object obj = new Object();

    public static void main(String[] args) {
                new Thread(() -> { 
            synchronized (obj) { 
                log.debug("执行...."); 
                try { 
                    obj.wait();
                } catch (InterruptedException e) { 
                    e.printStackTrace();
                } 
                log.debug("其它代码...."); // 断点
            }
        },"t1").start();

        new Thread(() -> { 
            synchronized (obj) { 
                log.debug("执行...."); 
                try { 
                    obj.wait();
                } catch (InterruptedException e) { 
                    e.printStackTrace();
                } 
                log.debug("其它代码...."); // 断点
            }
        },"t2").start();

        sleep(0.5);
        log.debug("唤醒 obj 上其它线程"); 
        synchronized (obj) {
            obj.notifyAll(); // 唤醒obj上所有等待线程  断点 
        }
    }
}

3、 RUNNABLE <–> WAITING

1)当前线程调用 t.join() 方法时,当前线程从 RUNNABLE --> WAITING
注意是当前线程在t 线程对象的监视器上等待

2)t 线程运行结束,或调用了当前线程的 interrupt() 时,当前线程从 WAITING --> RUNNABLE

4、RUNNABLE <–> WAITING

  • 当前线程调用 LockSupport.park() 方法会让当前线程从 RUNNABLE --> WAITING
  • 调用 LockSupport.unpark(目标线程) 或调用了线程 的 interrupt() ,会让目标线程从 WAITING --> RUNNABLE

5、RUNNABLE <–> TIMED_WAITING

t 线程用 synchronized(obj) 获取了对象锁后
调用 obj.wait(long n) 方法时,t 线程从 RUNNABLE --> TIMED_WAITING
t 线程等待时间超过了 n 毫秒,或调用 obj.notify() , obj.notifyAll() , t.interrupt() 时 竞争锁成功,t 线程从 TIMED_WAITING --> RUNNABLE
竞争锁失败,t 线程从 TIMED_WAITING --> BLOCKED

6、RUNNABLE <–> TIMED_WAITING

  • 当前线程调用 t.join(long n) 方法时,当前线程从 RUNNABLE --> TIMED_WAITING
    注意是当前线程在t 线程对象的监视器上等待
  • 当前线程等待时间超过了 n 毫秒,或t 线程运行结束,或调用了当前线程的 interrupt() 时,当前线程从 TIMED_WAITING --> RUNNABLE

7、RUNNABLE <–> TIMED_WAITING

  • 当前线程调用 Thread.sleep(long n) ,当前线程从 RUNNABLE --> TIMED_WAITING
  • 当前线程等待时间超过了 n 毫秒,当前线程从 TIMED_WAITING --> RUNNABLE

8、RUNNABLE <–> TIMED_WAITING

  • 当前线程调用 LockSupport.parkNanos(long nanos) 或 LockSupport.parkUntil(long millis) 时,当前线 程从 RUNNABLE --> TIMED_WAITING
  • 调用 LockSupport.unpark(目标线程) 或调用了线程 的 interrupt() ,或是等待超时,会让目标线程从
    TIMED_WAITING–> RUNNABLE

9、RUNNABLE <–> BLOCKED

  • t 线程用 synchronized(obj) 获取了对象锁时如果竞争失败,从 RUNNABLE --> BLOCKED
  • 持 obj 锁线程的同步代码块执行完毕,会唤醒该对象上所有 BLOCKED 的线程重新竞争,如果其中 t 线程竞争 成功,从 BLOCKED --> RUNNABLE ,其它失败的线程仍然 BLOCKED

10、RUNNABLE <–> TERMINATED

当前线程所有代码运行完毕,进入 TERMINATED

bj 锁线程的同步代码块执行完毕,会唤醒该对象上所有 BLOCKED 的线程重新竞争,如果其中 t 线程竞争 成功,从 BLOCKED --> RUNNABLE ,其它失败的线程仍然 BLOCKED

10、RUNNABLE <–> TERMINATED

当前线程所有代码运行完毕,进入 TERMINATED
Java创建线程的四种方式及其比较
Java线程常用方法详解
整理自黑马培训班笔记,侵删!!!

你可能感兴趣的:(并发多线程)