美文网首页
说一下Java线程状态及切换

说一下Java线程状态及切换

作者: 平凡的柚子 | 来源:发表于2020-12-26 22:24 被阅读0次

一、什么是Java线程状态

在Java程序中,用于描述Java线程的六种状态:

  • 新建(NEW):当前线程,刚刚新建出来,尚未启动。
  • 运行(RUNNABLE):当前线程,处于竞争CPU时间分片或已经获得CPU时间片的状态。
  • 等待(WAITTING):当前线程,处于休眠,不参与CPU时间片竞争的状态。
  • 定时等待(TIMED_WAITTING):当前线程,处于定时休眠,暂时不参与CPU时间片竞争的状态。
  • 阻塞(BLOCKED):当前线程,处于阻塞,不参与CPU时间片竞争的状态。
  • 终止(TERMINATED):当前线程,处于最终停止的状态。

新建状态,只能进入运行状态。而终止状态无法再转为其他状态。

等待/定时等待与阻塞,差别就是后者需要一个事件信号(如其他线程放弃当前线程需要的排他锁),才可以进行状态切换。当然,强行关闭也是可以的。

Java线程的实现并不受JVM规范约束,故不同虚拟机的实现,往往不同。目前主流的HotSpot是将每个Java线程直接映射到一个操作系统的原生线程,从而由操作系统完成一系列的线程调度

二、哪里看Java线程状态

查看Java线程状态,主要存在三种方式:

  • java.lang.Thread.State下可以直接看到Java的六种线程状态
  • Java运行时,程序内部可以通过Thread.getState()获取目标线程状态
  • Java运行时,程序外部可以通过jstack等工具,查看线程状态

有关jstack等工具等使用,后续会有博客,专门阐述。

三、什么时候变换Java线程状态

Java线程状态的切换嘛。不啰嗦,直接上图。


这张图涵盖了Java线程状态切换的各类方法。相较网上一些图片,更为详尽一些。
如果有所遗漏,可以告诉我,我会及时填补上。

四、谁在使用Java线程状态

日常开发中,我们并不会直接与线程状态进行交互。
我们往往直接使用JDK包装好的工具,如JUC包下的各类工具等。

举个栗子

线程池中的应用

位置:com.sun.corba.se.impl.orbutil.threadpool.ThreadPoolImpl#close


    // Note that this method should not return until AFTER all threads have died.
    public void close() throws IOException {

        // Copy to avoid concurrent modification problems.
        List<WorkerThread> copy = null;
        synchronized (workersLock) {
            copy = new ArrayList<>(workers);
        }

        for (WorkerThread wt : copy) {
            wt.close();
            while (wt.getState() != Thread.State.TERMINATED) {
                try {
                    wt.join();
                } catch (InterruptedException exc) {
                    wrapper.interruptedJoinCallWhileClosingThreadPool(exc, wt, this);
                }
            }
        }

        threadGroup = null;
    }

实际查看JDK后发现,JDK中其实也没有辣么多的实例,并且大多数直接关联线程状态的,也是一些状态查看的东东。
这在文章开头就说,Java线程操作,是很底层的,甚至其实现都不包含在虚拟机规范中。
主流的HotSpot,也是直接将Java线程映射到系统线程,由系统进行一系列的线程调度处理。
所以,在JDK中,是直接对线程状态进行处理的部分是很少的。

五、为什么需要线程状态

1.为什么需要线程状态这一概念

这个问题,可以从两个角度来说明:生命周期与资源管理

  • 一方面,线程状态很好地刻画了线程的整个生命周期,对生命周期中不同阶段进行了有效划分。
  • 另一方面,资源是有限的,需求是无限的。所以需要将系统资源有意识地进行调度,合理利用比较优势,追求帕累托最优。

实现后者的,就是利用线程在生命周期的不同阶段这一天然属性带来的状态刻画,进行的分组。CPU调度只需要关注运行状态的线程。而阻塞,等待等线程,都有着属于自己的一套处理方式。最终获得资源(开发时对复杂性的应对,运行时对系统资源对消耗,应用者心智模型的成长等)的优化分配。

2.JDK中为什么需要定义Java线程状态

前文有说到,Java中很少直接使用到线程状态。那么为什么还要在JDK中定义Java的六种线程状态呢?
一方面,通过信息透明的方式,降低使用者使用时建立心智模型的成本。如,现在的我们可以通过打印日志,打断点,快速了解Java的各个线程状态,并清楚了解产生的原因。从而大大提高了我们对Java线程的认识,进而更为愉快地拥抱JUC包下诸如线程池等工具。
另一方面,通过可以直接应用的状态枚举,我们可以很好地对现有工具进行二次开发等。如我们可以通过扩展AQS,并在其中添加线程状态的校验,从而得到定制化的线程同步工具。

六、如何使用线程状态

使用的方式,我已经在上文说了:学习Java线程,定制线程相关工具开发。
这里给出一个有关线程学习的demo:


/**
 * @program: learning
 * @description: 用于确认线程状态问题
 * @author: Jarry
 * @create: 2020-12-26 22:25
 **/
public class ThreadState {

    public static void main(String[] args) {
        threadStateTest();
//        threadStateTest2();
//        threadStateWithBlocked();
//        threadStateWithException();
//        threadStateWithSuspend();
    }

    /**
     * 实践证明:Thread.suspend()与Thread.resume()不会改变线程状态
     * 线程状态该是Waiting,就Waiting。该Timed_Waiting就Timed_Waiting
     * Thread.suspend()与Thread.resume()只是挂起目标线程(并且不会释放锁资源)
     */
    private static void threadStateWithSuspend() {
        Thread thread1 = new Thread(() -> {
//            LockSupport.park();
            LockSupport.parkNanos(2000000000);
        });

        thread1.start();
        printThreadState(thread1);
        LockSupport.parkNanos(500000000);
        printThreadState(thread1);
        thread1.suspend();
        printThreadState(thread1);
        LockSupport.parkNanos(500000000);
        printThreadState(thread1);
        thread1.resume();
        LockSupport.parkNanos(500000000);
        printThreadState(thread1);

//        LockSupport.unpark(thread1);
    }

    /**
     * 展现线程阻塞状态
     */
    private static void threadStateWithBlocked() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                synchronized (ThreadState.class) {
//                    LockSupport.parkNanos(2000000000);
                    LockSupport.park();
                }
            }
        };

        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);

        thread1.start();
        LockSupport.parkNanos(500000000);
        thread2.start();
        // 加上以下时间间隔,则结果:Runnable->Blocked
        // 推论:Thread.start()会将线程状态设置为Runnable,然后在遇到sync的锁,再切换为Blocked状态
//        LockSupport.parkNanos(500000000);

        printThreadState(thread2);
        LockSupport.parkNanos(500000000);
        printThreadState(thread2);

        LockSupport.parkNanos(500000000);
        LockSupport.unpark(thread1);
        LockSupport.unpark(thread2);

    }

    /**
     * 由于底层实现机制的不同(相较于其他waiting的方法),无法直接进行Object.wait(),否则会抛出以下异常
     * @exception java.lang.IllegalMonitorStateException
     * object.wait()进行wait的方法,是直接对其wait_set进行操作
     */
    private static void threadStateWithException() {
        Thread thread1 = new Thread(() -> {
            try {
                ThreadState.class.wait(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });

        thread1.start();
        LockSupport.parkNanos(1000000000);
        printThreadState(thread1);

    }

    /**
     * Object.wait()的使用
     */
    private static void threadStateTest3() {
        Thread thread1 = new Thread(() -> {
            synchronized (ThreadState.class) {
                try {
                    ThreadState.class.wait(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        thread1.start();
        LockSupport.parkNanos(1000000000);
        printThreadState(thread1);

    }

    /**
     * 确定LockSupport.parkNacos()是否可以生成Time_Waiting状态
     */
    private static void threadStateTest2() {
        Thread thread1 = new Thread(() -> {
            LockSupport.parkNanos(2000000000);
        });

        thread1.start();
        printThreadState(thread1);
        LockSupport.parkNanos(1000000000);

        printThreadState(thread1);
    }

    /**
     * 查看到除Blocked以外的所有线程状态
     */
    private static void threadStateTest() {
        Thread thread1 = new Thread(() -> {
            synchronized (ThreadState.class) {
                // Runnable
                printThreadState(Thread.currentThread());

                // 1.Thread.sleep(time)
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
                // 2.Object.wait(time)
//                try {
//                    ThreadState.class.wait(2000);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                // 3.Thread.join(time)
//                try {
//                    Thread.currentThread().join(2000);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                // 4.LockSupport.parkNanos(time);
//            LockSupport.parkNanos(2000000000);
                // 5.LockSupport.parkUntil(timeStamp);
//            LockSupport.parkUntil(System.currentTimeMillis()+2000);

                LockSupport.park();
            }

        });
        thread1.setName("test_thread");

        // New
        printThreadState(thread1);

        thread1.start();
        LockSupport.parkNanos(1000000000);
        // Timed_waiting
        printThreadState(thread1);

        LockSupport.parkNanos(2000000000);
        // Waiting
        printThreadState(thread1);

        LockSupport.unpark(thread1);

        LockSupport.parkNanos(1000000000);
        // Terminated
        printThreadState(thread1);

    }

    private static void printThreadState(Thread thread) {
        System.out.println("current Thread(" + thread.getName()+":" + thread.getId() + ") state:" + thread.getState());
    }

}

代码中有一些细碎的知识点,就不在这里赘述了。感兴趣的小伙伴,可以自己看看注释,自行验证。

七、扩展:系统状态(三态&五态)

操作系统就包含进程管理,作业管理,文件管理等。其中进程管理,就涉及系统状态的三态模型与五态模型。
其中,三态模型包含以下三种状态:

  • 就绪状态
  • 运行状态
  • 阻塞状态

而五态模型则包含以下五种状态:

相关文章

网友评论

      本文标题:说一下Java线程状态及切换

      本文链接:https://www.haomeiwen.com/subject/lslnnktx.html