四.图解线程生命周期

12 篇文章 0 订阅
8 篇文章 0 订阅
本文详细解析了Java线程的六个生命周期状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,并通过代码示例展示了状态之间的转换过程。着重介绍了线程在不同状态下的行为以及如何在特定条件下触发状态转变。
摘要由CSDN通过智能技术生成

四.图解线程生命周期

线程的一生,六个状态(生命周期)

public enum State {
 		//新建
        NEW,
		//可运行
        RUNNABLE,
		//阻塞
        BLOCKED,
		//等待		
        WAITING,
		//计时等待
        TIMED_WAITING,
		//终止
        TERMINATED;
    }

每个状态的含义

New

已创建,但是还未启动的新线程.也就是已经new出来了,但是还没有调用start()

Runnable

当start()被调用后,就会处于runnable(可运行的)状态,运行于JVM中.但是可能还在等待操作系统的其它资源(例如调度器分配的CPU时间片)

如果在运行中持有的CPU时间片被调度走了,这时当前执行状态会保存在当前栈和程序计数器中,依旧为runnable状态(随时等待被分配时间片).当CPU时间片又分配了,则从栈和程序计算器中恢复线程执行状态,继续执行.

对应OS的两种状态,ready和running;

Blocked

当将要进入synchronized方法/代码块的时候,尝试获取monitor lock,但是失败了,且获得monitor lock的线程还没有退出synchronized方法/代码块,这时处于阻塞状态.

还有,如果已经处于synchronized代码块/方法中,从wait()方法中被唤醒后,尝试获取synchronized 的monitor lock失败,也将处于阻塞状态

这时都是在等待一个monitor lock,已进入synchronized方法/代码块

案例

代码

    public static void main(String[] args) {
        synchronized (SynchronizedTest.class) {
            System.out.println("synchronized");
        }
    }

反编译 javap -c

 public static void main(java.lang.String[]);
    Code:
    //将SynchronizedTest.class对象压入栈顶
       0: ldc           #2                  // class com/example/threadCoreKnowledge/stopThread_3/SynchronizedTest
       //复制一个SynchronizedTest.class引用到栈顶
       2: dup
       //将栈顶引用型数值存入第二个本地变量
       3: astore_1
       //消耗栈顶元素,获取对应的锁,
       //用于同步方法或同步块->synchronized(SynchronizedTest.class){
       4: monitorenter
       5: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
       8: ldc           #4                  // String synchronized
      10: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       //获取之前存入的复制品放入栈顶
      13: aload_1
       //消耗栈顶元素,释放对应的锁,用于同步方法或同步块->       }
      14: monitorexit
      15: goto          23
      //异常处理流程,确保会释放锁{
      //将当前栈顶异常存入第三个本地变量
      18: astore_2
      //获取之前存入的复制品放入栈顶
      19: aload_1
      //消耗栈顶元素,释放对应的锁,
      20: monitorexit
      //加载异常到栈顶
      21: aload_2
      //抛出异常
      22: athrow
      //}异常处理流程
      23: return
    Exception table:
//	   start  end  handle ExceptionType
       from    to  target type
    //代表第5行到第15行的任意异常转入第18行处理
           5    15    18   any
    //代表第18行到第21行的任意异常转入第18行处理
          18    21    18   any

Waiting

1.没有设置timeout参数的Object.wait()方法.

2.没有设置timeout参数的Thread.join方法.

3.没有设置timeout参数的LockSupport.park()方法.

/*Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:
Object.wait with no timeout
Thread.join with no timeout
LockSupport.park
A thread in the waiting state is waiting for another thread to perform a particular action. For example, a thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object. A thread that has called Thread.join() is waiting for a specified thread to terminate.
*/
WAITING

Timed_Waiting

/*Thread state for a waiting thread with a specified waiting time. A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:
具有指定等待时间的等待线程的线程状态。线程由于以指定的正数等待时间调用以下方法之一而处于定时等待状态
Thread.sleep
Object.wait with timeout
Thread.join with timeout
LockSupport.parkNanos
LockSupport.parkUntil
*/    TIMED_WAITING

Terminated

/*Thread state for a terminated thread. The thread has completed execution.
线程状态是一个终止线程。代表线程已完成执行(run方法)或者出现一个未被捕获的异常,导致程序意外终止(run未执行完毕)
*/
TERMINATED;

状态间的转化图示

以下图示描述线程正常状态下的状态转换
在这里插入图片描述

代码案例

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                while (!Thread.currentThread().isInterrupted()) {
                    synchronized (Thread.class) {
                        Thread.class.wait();
                        break;
                    }
                }
            } catch (InterruptedException e) {
                System.out.println(e);
                try {
                    //报错后睡眠10秒,便于打印出Timed_Waiting
                    Thread.sleep(10000);
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
            }
        });
        synchronized (Thread.class) {
            //打印New
            System.out.println("thread>>>" + thread.getState());
            thread.start();
            //打印runnable
            System.out.println("thread>>>" + thread.getState());
            //睡眠一小会,确保thread获得时间片开始运行
            Thread.sleep(1);
        }
        //这时虽然已经归还锁了,但是因为Cpu执行很快,所以thread可能还没有
        //获取锁仍然处于BLOCKED状态
        //这个由于调度器分配时间片的不确定性,需要多执行几次,才能看到
        //BLOCKED效果
        System.out.println("thread>>>" + thread.getState());
        //由于thread获取时间片后立马调用Thread.class.wait();,所以这里是WAITING
        System.out.println("thread>>>" + thread.getState());
        //中断thread线程,使其进入catch块中,执行Thread.sleep(10000);
        thread.interrupt();
        //睡眠一秒,确保Thread.sleep(10000);已被执行
        Thread.sleep(1000);
        //这时thread已经进入sleep(10000)中,所以是TIMED_WAITING
        System.out.println("thread>>>" + thread.getState());
        //等待线程执行结束
        Thread.sleep(11000);
        //thread线程已结束,所以是TERMINATED
        System.out.println("thread>>>" + thread.getState());
    }

结果

thread>>>NEW
thread>>>RUNNABLE
thread>>>BLOCKED
thread>>>WAITING
java.lang.InterruptedException
thread>>>TIMED_WAITING
thread>>>TERMINATED

Process finished with exit code 0

最后要注意的是,图左边的三个状态是不能回头的.

例如无法从Runnable回到New

(正常状态下)全部的状态都是无法跳跃的,只能按箭头转到某一个再到另一个,而不能无视箭头连接间间隔的哪个.

例如,无法从New直接到Terminated,也无法从New直接到Blocked,这些转变都需要经历Runnable状态

特殊情况下,如线程刚从waiting中被唤醒,但是唤醒它的线程还没有退出释放到锁,于是被唤醒的线程就处于Blocked状态.

还有,当在waiting中如果爆出一个未被捕获的错误,也会直接从waiting跳过runnable直接变为terminated

阻塞状态是什么

一般习惯而言,把Blocked(阻塞),Waiting(等待),Timed_waiting(计时等待)都称为阻塞状态

因为这三者都让线程从运行状态停止了.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值