美文网首页Java工程师知识树
Java基础-线程-线程的状态

Java基础-线程-线程的状态

作者: HughJin | 来源:发表于2021-01-30 08:30 被阅读0次

Java工程师知识树 / Java基础


线程状态

每一个线程都有自己的局部变量表、程序计数器,以及生命周期等,线程的生命周期中各个阶段的状态包括:

NEW(初始化),
RUNNABLE(可运行的),
BLOCKED(锁定或阻塞),
WAITING(等待),
TIMED_WAITING(定时等待),
TERMINATED(结束);
在Thread内部类java.lang.Thread.State中定义了线程的生命周期中的所有状态
public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
}

获取线程的状态方法:java.lang.Thread#getState

public State getState() {
    // get current thread state 获取当前线程的线程状态
    return sun.misc.VM.toThreadState(threadStatus);
}

各个状态详情介绍:

1. 新建状态(new):

​ NEW状态为使用new创建一个线程对象,在堆中分配内存空间在调用start方法之前的线程所处的状态;在此状态下,线程还没启动,只是创建了一个线程对象存储在堆中;比如:

Thread t = new Thread(); // 此时t就属于新建状态

​ 当新建状态下的线程对象调用了start方法,该线程对象就从新建状态进入可运行状态(runnable)

​ 线程对象的start方法只能调用一次,多次调用会发生IllegalThreadStateException

2. 可运行状态(runnable):

​ 又可以细分成两种状态,readyrunning,分别表示就绪状态运行状态。将可运行状态细分为两种状态是因为不确定线程是否获取到CPU时间片。

就绪状态:线程对象调用start方法之后,等待JVM的调度(此时该线程并没有运行),还未开始运行;

运行状态:线程对象已获得JVM调度,处在运行中;如果存在多个CPU,那么允许多个线程并行运行;

3. 阻塞状态(blocked):

​ 处于运行中的线程因为某些原因放弃CPU时间片暂时停止运行,就会进入阻塞状态;此时JVM不会给线程分配CPU时间片,直到线程重新进入就绪状态(ready)才有可能转到运行状态;

阻塞状态只能先进入就绪状态,进而由操作系统转到运行状态,不能直接进入运行状态;

​ 阻塞状态产生的情况:

  • 当A线程处于运行中,试图获取同步锁时,但同步锁却被B线程获取,此时JVM会把A线程存到共享资源对象的锁池中,A线程进入阻塞状态;
  • 当线程处于运行状态,发出了IO请求时,该线程会进入阻塞状态;
4. 等待状态(waiting):

运行中的线程调用了wait方法(无参数的wait方法),然后JVM会把该线程储存到共享资源的对象等待池中,该线程进入等待状态;处于该状态中的线程只能被其他线程唤醒(notify)

5. 计时等待状态(timed waiting):

运行中的线程调用了带参数的wait方法或者sleep方法,线程进入计时等待状态

计时等待状态下的线程不会释放同步锁/同步监听器;

​ 计时等待状态产生的情况:

  • 当处于运行中的线程,调用了wait(long time)方法,JVM会把当前线程存在共享资源对象等待池中,线程进入计时等待状态;
  • 当前线程执行了sleep(long time)方法,该线程进入计时等待状态;
6. 终止状态(terminated):

​ 也可以称为死亡状态,表示线程终止,它的生命走到了尽头;线程一旦终止,就不能再重启启动,否则会发生IllegalThreadStateException;

​ 终止状态产生的情况:

  • 正常执行完run方法而退出,寿终正寝,属于正常死亡;
  • 线程执行遇到异常而退出,线程中断,属于意外死亡;

线程的生命周期状态图:

线程状态

上图解读:

  1. 一个线程在其被创建之后它将处于 NEW(新建)状态,调用runnable.start()方法后开始运行,这时线程将转换为RUNNABLE状态。RUNNABLE共有2种状态,就绪(READY)和运行中(RUNNING),当线程获得了 cpu 时间片(timeslice)后就处于 RUNNING(运行) 状态,未获得就处于READY(就绪)状态
  2. RUNNABLE状态,我们可以转换为waiting,time_waitingblocked三种状态。
  3. 进入waiting状态可以执行wait()等方法,而waiting状态转换为running状态可以通过notify等方法。
  4. 进入time_waiting状态可以通过sleep(long millis)方法或 wait(long millis),返回runnbale状态则可以通过notify等方法。
  5. 线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到 BLOCKED(阻塞) 状态
  6. 线程在执行完Runnable 的run()方法之后将会进入到 TERMINATED(终止) 状态

测试线程状态代码

package com.thread.study;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;

import java.util.Date;

public class TestThreadState {

    public static void main(String[] args) throws InterruptedException {
        final long ONE_SECONDS = 1000; // 1秒
        Thread mark = new Thread(() -> { // --> NEW
            synchronized (args) {
                try {
                    blocking(ONE_SECONDS); // --> BLOCKED
                    args.wait(); // --> WAITING
                    args.wait(ONE_SECONDS); // --> TIMED_WAITING
                } catch (InterruptedException e) {
                }
            }
        },"测试状态的线程");
        printThreadState(mark);
        new Thread(() -> { // 执行使 mark 线程启动后进入监视器锁定阻塞的线程(等待获取锁)
            try {
                blocking(ONE_SECONDS + 500);
            } catch (InterruptedException e) {
            }
        }).start();
        Thread.sleep(ONE_SECONDS / 10);
        mark.start(); // 启动 mark 线程 --> RUNNABLE
        printThreadState(mark); // 打印 mark 线程 start() 后的状态
        Thread.sleep(ONE_SECONDS / 10);
        printThreadState(mark); // 打印 mark 线程 等待获取 sync 的状态
        Thread.sleep(ONE_SECONDS * 2 + 500); // 等待 mark 线程 blocking() 执行完成后执行 wait()
        printThreadState(mark); // 打印 mark 线程 wait() 时的状态
        synchronized (args) {
            args.notify(); // 唤醒 mark 线程
        }
        Thread.sleep(ONE_SECONDS / 2); // 等待 mark 线程执行 wait(long timeout)
        printThreadState(mark); // 获取 mark 线程 wait(long timeout) 时的状态
        Thread.sleep(ONE_SECONDS); // 等待 mark 线程执行完毕
        printThreadState(mark); // 打印已执行完成的状态 --> TERMINATED
    }

    static synchronized void blocking(long timeout) throws InterruptedException {
        Thread.sleep(timeout);
    }

    static void printThreadState(Thread stateThread) {
        System.out.println(stateThread.getName() + DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MS_PATTERN) + "的线程状态为" + stateThread.getState());
    }
}

打印结果:

测试状态的线程2021-01-29 21:35:07.732的线程状态为NEW
测试状态的线程2021-01-29 21:35:07.935的线程状态为RUNNABLE
测试状态的线程2021-01-29 21:35:08.036的线程状态为BLOCKED
测试状态的线程2021-01-29 21:35:10.536的线程状态为WAITING
测试状态的线程2021-01-29 21:35:11.037的线程状态为TIMED_WAITING
测试状态的线程2021-01-29 21:35:12.039的线程状态为TERMINATED

相关文章

  • 多线程知识点整理

    1、多线程基础 线程的生命周期(状态)NEW:就绪状态Java线程刚刚被创建,调用start()方法之后不代表线程...

  • 多线程总结

    线程基础 线程的状态 根据java官方的定义,线程一共有五种状态NEW、RUNNABLE、BLOCKED、WAIT...

  • Java并发编程(二)同步

    如果你的java基础较弱,或者不大了解java多线程请先看这篇文章java多线程(一)线程定义、状态和属性 同步一...

  • Java基础-线程-线程的状态

    Java工程师知识树[https://www.jianshu.com/p/db77d19a25f6] / Ja...

  • java多线程基础

    多线程是java基础中不可或缺的一块内容,本文主要介绍java线程使用方法,线程同步,线程状态及基本方法;在这里我...

  • 多线程 | 4.线程池

    Java并发编程:线程池的使用 线程池基础 请求队列 线程池维护一定数量的线程,当线程池在运行状态的线程数量达上...

  • Java高级工程师学习路径

    第一章 多线程并发编程 1.1 Java基础 1.1.1 JAVA程序运行堆栈分析1.1.2 线程状态1.1.3 ...

  • 总结多线程与设计模式+synchronized+性能+高吞吐+死

    Java线程 Java语言的线程 何谓线程 线程启动 线程的暂时停止 线程的共享互斥 线程的协调 线程的状态转移 ...

  • Java多线程目录

    Java多线程目录 Java多线程1 线程基础Java多线程2 多个线程之间共享数据Java多线程3 原子性操作类...

  • Java线程简介

    本文将介绍Java线程的状态、线程的中断、线程间通信和线程的实现。 线程的状态 Java语言定义了6种不同的线程状...

网友评论

    本文标题:Java基础-线程-线程的状态

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