java线程状态流转

发布时间:2024-01-18 22:49:11

本文主要分析jvm中涉及的线程状态以及这些状态的流转关系


wait和notify方法的执行前提是调用该方法的线程必须拿到该对象的监视器锁


一、jvm线程状态总览

点开Thread类中的内部枚举类Thread#State可以见注释,jvm中的线程状态主要分为以下六种:
在这里插入图片描述

	NEW				(还没有启动的线程)
	RUNNABLE		(在jvm中执行)
	BLOCKED			(被阻塞,等待获取监视器锁)
	WAITTING		(无限期地等待另一个线程执行特定操作,如notify)
	TIMED_WAITTING	(等待另一个线程执行操作长达指定等待时间)
	TERMINATED		(已退出)

一个线程在同一时刻有且只能有一种状态,该状态属于jvm虚拟机范畴内的状态,不反映任何操作系统层面的线程状态。

二、状态流转

这6中线程状态中,我们主要关注以下三种状态:BLOCKED、WAITTING、TIMED_WAITTING。
在这里插入图片描述

BLOCKED

等待锁的时候会被阻塞,获取到锁后变为RUNNABLE状态

WAITTING

当线程调用wait方法、join方法以及park方法后进入挂起状态,相应的调用notify方法以及unpark方法后恢复为RUNNABLE状态。

TIMED_WAITTING

与WAITTING状态基本一致,区别在于挂起的状态有超时时间。

需要注意,RUNNABLE状态实际细分为ready和running状态,线程刚start时不会直接获取到cpu的时间片执行任务,而是处于就绪状态(ready)被统一放入就绪队列中,等待着jvm的线程调度器进行调度,只有真正被调度起来才是running状态

三、wait-notify的正确搭配使用方式

还是参考Object类的源码:

wait方法:
在这里插入图片描述

notify方法:
在这里插入图片描述

可见,wait和notify方法的执行前提是调用该方法的线程必须拿到该对象的监视器锁,否则必定会抛出IllegalMonitorStateException异常,这是jvm的规定。

那么wait和notify方法配合使用的正确打开方式如下:

public class TestThreadState {
    public static void main(String[] args) throws InterruptedException {

        final long SLEEP = 1L;
        final Object lock = new Object();

        new Thread(() -> {
            long start = System.currentTimeMillis();
            synchronized (lock) {
                try {
                    System.out.println("线程1获取到锁");
                    TimeUnit.SECONDS.sleep(SLEEP);
                    System.out.println("线程1即将调用wait方法,挂起当前线程并释放锁");
                    // 执行wait方法,挂起当前线程并释放锁
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程1执行耗时:" + (System.currentTimeMillis() - start));
        }).start();

        // 让线程1获取到时间片获取到监视器锁(注意这里和线程1睡眠保持了一致)
        TimeUnit.SECONDS.sleep(SLEEP);

        new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("线程2获取到锁");
                    TimeUnit.SECONDS.sleep(3);
                    lock.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

执行结果打印:

线程1获取到锁
线程1即将调用wait方法,挂起当前线程并释放锁
线程2获取到锁
线程1执行耗时:4015

执行代码可以看到流程为:
1、线程1调用wait方法使得当前线程挂起并释放监视器锁
2、线程2这时候获取到锁,进入同步块执行业务,结束后调用notify方法唤醒其他线程并退出同步块,释放监视器锁。
3、线程1恢复到RUNNABLE状态


文章来源:https://blog.csdn.net/niceHack/article/details/135563821
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。