首页 > 编程语言 >线程的6种状态(juc编程)

线程的6种状态(juc编程)

时间:2024-06-20 21:54:31浏览次数:22  
标签:juc getState thread Thread 状态 编程 start 线程

1 线程状态

1.1 状态介绍

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。线程对象在不同的时期有不同的状态。那么Java中的线程存在哪几种状态呢?Java中的线程

状态被定义在了java.lang.Thread.State枚举类中,State枚举类的源码如下:

public class Thread {
    
    public enum State {
    
        /* 新建 */
        NEW , 

        /* 可运行状态 */
        RUNNABLE , 

        /* 阻塞状态 */
        BLOCKED , 

        /* 无限等待状态 */
        WAITING , 

        /* 计时等待 */
        TIMED_WAITING , 

        /* 终止 */
        TERMINATED;
    
	}
    
    // 获取当前线程的状态
    public State getState() {
        return jdk.internal.misc.VM.toThreadState(threadStatus);
    }
    
}

通过源码我们可以看到Java中的线程存在6种状态,每种线程状态的含义如下

线程状态 具体含义
NEW 一个尚未启动的线程的状态。也称之为初始状态、开始状态。线程刚被创建,但是并未启动。还没调用start方法。MyThread t = new MyThread()只有线程象,没有线程特征。
RUNNABLE 当我们调用线程对象的start方法,那么此时线程对象进入了RUNNABLE状态。那么此时才是真正的在JVM进程中创建了一个线程,线程一经启动并不是立即得到执行,线程的运行与否要听令与CPU的调度,那么我们把这个中间状态称之为可执行状态(RUNNABLE)也就是说它具备执行的资格,但是并没有真正的执行起来而是在等待CPU的度。
BLOCKED 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
WAITING 一个正在等待的线程的状态。也称之为等待状态。造成线程等待的原因有两种,分别是调用Object.wait()、join()方法。处于等待状态的线程,正在等待其他线程去执行一个特定的操作。例如:因为wait()而等待的线程正在等待另一个线程去调用notify()或notifyAll();一个因为join()而等待的线程正在等待另一个线程结束。
TIMED_WAITING 一个在限定时间内等待的线程的状态。也称之为限时等待状态。造成线程限时等待状态的原因有三种,分别是:Thread.sleep(long),Object.wait(long)、join(long)。
TERMINATED 一个完全运行完成的线程的状态。也称之为终止状态、结束状态

各个状态的转换,如下图所示:

1.2 案例演示

为了验证上面论述的状态即状态转换的正确性,也为了加深对线程状态转换的理解,下面通过三个案例演示线程间中的状态转换。

1.2.1 案例一

本案例主要演示TIME_WAITING的状态转换。

需求:编写一段代码,依次显示一个线程的这些状态:NEW -> RUNNABLE -> TIME_WAITING -> RUNNABLE -> TERMINATED

为了简化我们的开发,本次我们使用匿名内部类结合lambda表达式的方式使用多线程。

代码实现

public class ThreadStateDemo01 {

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

        //定义一个内部线程
        Thread thread = new Thread(() -> {
            System.out.println("2.执行thread.start()之后,线程的状态:" + Thread.currentThread().getState());
            try {
                //休眠100毫秒
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("4.执行Thread.sleep(long)完成之后,线程的状态:" + Thread.currentThread().getState());
        });

        //获取start()之前的状态
        System.out.println("1.通过new初始化一个线程,但是还没有start()之前,线程的状态:" + thread.getState());

        //启动线程
        thread.start();

        //休眠50毫秒
        Thread.sleep(50);

        //因为thread1需要休眠100毫秒,所以在第50毫秒,thread处于sleep状态
        //用main线程来获取thread1线程的状态,因为thread1线程睡眠时间较长
        //所以当main线程执行的时候,thread1线程还没有睡醒,还处于计时等待状态
        System.out.println("3.执行Thread.sleep(long)时,线程的状态:" + thread.getState());

        //thread1和main线程主动休眠150毫秒,所以在第150毫秒,thread早已执行完毕
        Thread.sleep(100);

        System.out.println("5.线程执行完毕之后,线程的状态:" + thread.getState() + "\n");

    }

}

控制台输出

1.通过new初始化一个线程,但是还没有start()之前,线程的状态:NEW
2.执行thread.start()之后,线程的状态:RUNNABLE
3.执行Thread.sleep(long)时,线程的状态:TIMED_WAITING
4.执行Thread.sleep(long)完成之后,线程的状态:RUNNABLE
5.线程执行完毕之后,线程的状态:TERMINATED

1.2.2 案例二

本案例主要演示WAITING的状态转换。

需求:编写一段代码,依次显示一个线程的这些状态:NEW -> RUNNABLE -> WAITING -> RUNNABLE -> TERMINATED

public class ThreadStateDemo02 {

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

        //定义一个对象,用来加锁和解锁
        Object obj = new Object();

        //定义一个内部线程
        Thread thread1 = new Thread(() -> {
            System.out.println("2.执行thread.start()之后,线程的状态:" + Thread.currentThread().getState());
            synchronized (obj) {
                try {

                    //thread1需要休眠100毫秒
                    Thread.sleep(100);

                    //thread1100毫秒之后,通过wait()方法释放obj对象是锁
                    obj.wait();
                    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("4.被object.notify()方法唤醒之后,线程的状态:" + Thread.currentThread().getState());
        });

        //获取start()之前的状态
        System.out.println("1.通过new初始化一个线程,但是还没有start()之前,线程的状态:" + thread1.getState());

        //启动线程
        thread1.start();

        //main线程休眠150毫秒
        Thread.sleep(150);

        //因为thread1在第100毫秒进入wait等待状态,所以第150秒肯定可以获取其状态
        System.out.println("3.执行object.wait()时,线程的状态:" + thread1.getState());

        //声明另一个线程进行解锁
        new Thread(() -> {
            synchronized (obj) {
                //唤醒等待的线程
                obj.notify();
            }
        }).start();

        //main线程休眠10毫秒等待thread1线程能够苏醒
        Thread.sleep(10);

        //获取thread1运行结束之后的状态
        System.out.println("5.线程执行完毕之后,线程的状态:" + thread1.getState() + "\n");

    }

}

控制台输出结果

1.通过new初始化一个线程,但是还没有start()之前,线程的状态:NEW
2.执行thread.start()之后,线程的状态:RUNNABLE
3.执行object.wait()时,线程的状态:WAITING
4.被object.notify()方法唤醒之后,线程的状态:RUNNABLE
5.线程执行完毕之后,线程的状态:TERMINATED

1.2.3 案例三

本案例主要演示BLOCKED的状态转换。

需求:编写一段代码,依次显示一个线程的这些状态:NEW -> RUNNABLE -> BLOCKED -> RUNNABLE -> TERMINATED

public class ThreadStateDemo03 {

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

        //定义一个对象,用来加锁和解锁
        Object obj2 = new Object();

        //定义一个线程,先抢占了obj2对象的锁
        new Thread(() -> {
            synchronized (obj2) {
                try {
                    Thread.sleep(100);              //第一个线程要持有锁100毫秒
                    obj2.wait();                          //然后通过wait()方法进行等待状态,并释放obj2的对象锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //定义目标线程,获取等待获取obj2的锁
        Thread thread = new Thread(() -> {
            System.out.println("2.执行thread.start()之后,线程的状态:" + Thread.currentThread().getState());
            synchronized (obj2) {
                try {
                    Thread.sleep(100);              //thread3要持有对象锁100毫秒
                    obj2.notify();                        //然后通过notify()方法唤醒所有在ojb2上等待的线程继续执行后续操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("4.阻塞结束后,线程的状态:" + Thread.currentThread().getState());
        });

        //获取start()之前的状态
        System.out.println("1.通过new初始化一个线程,但是还没有thread.start()之前,线程的状态:" + thread.getState());

        //启动线程
        thread.start();

        //先等100毫秒
        Thread.sleep(50);

        //第一个线程释放锁至少需要100毫秒,所以在第50毫秒时,thread正在因等待obj的对象锁而阻塞
        System.out.println("3.因为等待锁而阻塞时,线程的状态:" + thread.getState());

        //再等300毫秒
        Thread.sleep(300);

        //两个线程的执行时间加上之前等待的50毫秒总共是250毫秒,所以第300毫秒,所有的线程都已经执行完毕
        System.out.println("5.线程执行完毕之后,线程的状态:" + thread.getState());

    }

}


//---------------------代码简化--------------------------------------------
Object obj = new Object();

        Thread t1 = new Thread(()->{
            synchronized (obj){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();


        Thread t2 = new Thread(()->{
            System.out.println("线程开启之后的状态" + Thread.currentThread().getState());
            synchronized (obj){
                System.out.println("进入之后的状态" + Thread.currentThread().getState());
            }
        });



        System.out.println("创建线程对象后,但是不调用start方法的状态" + t2.getState());
        t2.start();
        Thread.sleep(100);
        System.out.println(t2.getState());
        Thread.sleep(2000);
        System.out.println(t2.getState());

控制台输出结果

1.通过new初始化一个线程,但是还没有thread.start()之前,线程的状态:NEW
2.执行thread.start()之后,线程的状态:RUNNABLE
3.因为等待锁而阻塞时,线程的状态:BLOCKED
4.阻塞结束后,线程的状态:RUNNABLE
5.线程执行完毕之后,线程的状态:TERMINATED

通过上面3个案例的代码演示,我们可以证明开始章节说所述的线程状态以及线程状态转换都是正确的。

标签:juc,getState,thread,Thread,状态,编程,start,线程
From: https://www.cnblogs.com/yes-yeah/p/18250593

相关文章

  • java多线程
    目录多线程的实现方式多线程的第一种实现方式 继承Thread类的方式进行实现多线程的第二种实现方式 实现Runnable接口的方式进行实现利用Callable接口和Future接口方式实现 多线程中常用的成员方法 StringgetName()                返回此线程的名......
  • Java学习基础笔记——多线程基础部分
    第十三章多线程基础13.1线程介绍13.1.1线程相关概念13.2线程创建13.2.1创建线程的两种方式13.2.2继承Threadvs实现Runnable的区别13.2.3线程终止13.3线程方法13.3.1常用方法第一组13.3.2常用方法第二组13.3.3用户线程和守护线程13.4Synchronized13......
  • 算法题---五个线程排序输出
    1、五个线程编号1、2、3、4、5,每个线程的执行完成时间不确定,要求按照排号顺序输出各个线程的结果,并且不能等所有线程执行完毕再排序输出,比如线程2先于线程1执行完了此时还不能输出。要等线程1输出完之后才能输出,其他线程以此类推方案一、利用所得传递,创建五把锁lock1、2、3、4......
  • Shell 编程之正则表达式与文本处理器
    Shell编程之正则表达式与文本处理器一、正则表达式基础正则表达式元字符总结二、文本处理器sed工具awk工具sort工具uniq工具tr工具三、总结在Shell编程中,正则表达式(RegularExpression)和文本处理器(如grep,sed,awk等)是两个极其重要的工具,它们允许我们以复杂......
  • 如何实现多线程下载大文件
    如何实现多线程下载大文件在应用开发中,实现多线程下载大文件是一个常见的需求,可以有效提高下载效率和用户体验。以下是实现多线程下载大文件的详细步骤和知识点:实现步骤:使用request模块:request模块提供了文件上传下载的基础能力,支持任务管理系统的默认并发功能,简化了下......
  • shell编程规范与变量(shell脚本)
    一、Shell的介绍二、Shell的概述三、Shell的作用在一些复杂的 Linux 维护工作中,大量重复性的输入和交互操作不仅费时费力,而且容易出错,而编写一个恰到好处的 Shell 脚本程序,可以批量处理、自动化地完成一系列维护任务,大大减轻管理员的负担。常见的 Shell 解释器程序......
  • 6.3实验五 数据库编程
    实验五 数据库编程一、实验目的熟悉并掌握嵌入式SQL编程、使用数据库访问接口技术实现对数据库的访问。二、实验要求熟悉使用嵌入式SQL编程访问数据库,熟悉VB中开发数据库应用程序的过程。三、实验步骤设计一个小型的数据库应用程序 1. 基本表建立(1)教师表建立Xum......
  • 深入理解AQS:Java并发编程中的核心组件
    目录AQS简介AQS的设计思路AQS的核心组成部分状态(State)同步队列(SyncQueue)条件队列(ConditionQueue)AQS的内部实现节点(Node)锁的获取与释放独占锁共享锁条件变量AQS的应用案例ReentrantLockCountDownLatchSemaphore总结参考文献AQS简介AbstractQueuedSynchronizer(AQ......
  • 如何看待国产显卡,摩尔线程的卡适合不适合购买 —— 适合当作手办,适合支持国货发展进行
    本文主要要说的是摩尔线程的显卡,不过在这之前先说下华为的显卡,华为的显卡只能说归,同等性能的卡价格估计是美国成熟品牌的数倍,这个情况来说,如果你不是政府采购,或者出于战略目的(防止被美国完全切断nvidia的销售以做备选),或者因为其他的复杂合作关系(国内各公司之间的混乱合作关系所影......
  • 【JavaEE精炼宝库】多线程(7)定时器
    目录一、定时器的概念二、标准库中的定时器三、自己实现一个定时器3.1MyTimerTask实现:3.2MyTimer实现:一、定时器的概念定时器也是软件开发中的⼀个重要组件。类似于一个"闹钟"。达到一个设定的时间之后,就执行某个指定好的代码(可以用来完成线程池里面的非核心线程......