六种线程状态详解

2023-11-12

1 线程状态概述

线程从创建到运行到结束是一个线程的生命周期,当线程被创建到结束过程中,不是一直处于运行状态的,下面来介绍一下线程从运行到结束所有的状态.

线程状态 导致状态发生条件
NEW(新建) 线程刚被创建,没有启动,也就是还没调用start()方法.MyThread t = new MyThread只有线程对象,没有线程特征。
Runnable(可运行) 这个时候线程已经调用了start方法,进入可运行状态
Blocked(锁阻塞) 当一个线程想要获取一个对象锁,而该对象锁被其他线程持有,该线程就进入了锁阻塞状态,当该线程得到锁对象时,就变成了Runnable(可运行)状态.
Waiting(无限等待) 一个线程等待另一个线程被notify(唤醒)的动作时,该线程进入无限等待状态,这个状态是不自动唤醒的,只有等待另一个线程被notify之后才能够被唤醒.
Timed Waiting(计时等待) sleep设置的时间超时了,wait时间超时抢到了锁对象或中途被notify之后抢到了锁对象,在这个过程中,是计时等待状态
Teminated(被终止) 有三种情况:调用了stop方法、正常退出run方法正常死亡、出现了异常没有捕获到

接下来看一下详细图解:
在这里插入图片描述

2 sleep与wait

  • sleep(time):线程睡眠,让线程睡眠指定的毫秒数,在线程睡眠过程中,该线程是不会释放锁对象的,也可以说sleep(time)是个自私的,在该线程睡眠时间结束之后,锁对象才会被释放.
  • wair(time):线程等待,在线程等待过程中呢,会释放锁,较sleep而言,比较无私,在释放了锁对象之后,设置的时间超时,该线程不会继续往下执行了,需要重新获取锁对象才能继续执行,否则原地等待,如果没有抢到锁,该线程会进入锁阻塞的状态.
  • 或者,wait(time)中途被notify(唤醒),需要重新获取锁对象,如果抢到锁了,会继续执行,如果没有抢到锁,该线程会进入锁阻塞的状态.

3 等待与唤醒

wait与notify
两个都是Object类中的方法,这两个方法必须在同一个锁对象中,
wari一旦进入无限等待状态,会释放锁,往后背notify唤醒之后,也需要重新抢锁,抢到了,继续执行,抢不到,锁阻塞.

**notify:**唤醒一条等待的线程,如果有多个线程需要被唤醒,notify会在其中随机唤醒一个.

4 案例演示

 public class MyThread {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> list = new ArrayList<>();

        //创建存数据的线程

        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    synchronized (list){
                        //判断集合中有没有元素
                        if (list.size()!=0){
                            //线程等待
                            try {
                                list.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        //添加元素
                        list.add("张三");
                        System.out.println(list);

                        //唤醒取数据的线程
                        list.notify();
                    }
                }
            }
        }).start();

        //创建取数据的线程

        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    synchronized (list){
                        //判断集合中有没有元素
                        if (list.size()==0){
                            //线程等待
                            try {
                                list.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                        //获取元素
                        list.remove(0);
                        System.out.println(list);

                        //唤醒存数据的线程
                        list.notify();
                    }
                }
            }
        }).start();
    }
}

5 扩展练习

需求:

请用“等待唤醒”机制编写一个程序,要求:
第一个线程:遍历1–1000所有的数字,在遍历过程中,如果发现这个数字能 同时被2,3,5,7整除,立即wait()退出等待,让第二个线程进入。
第二个线程:运行后,将一个计数器 + 1,之后再唤醒等待的线程。
主线程中:休息2秒,让两个线程全部执行完毕,打印“计数器”的结果。


public class Test {
    public static void main(String[] args) {
        Lock lock = new Lock();
        //创建线程
        Thread1 thread1 = new Thread1(lock);
        thread1.start();

        Thread2 thread2 = new Thread2(lock);
        thread2.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("计数器结果是:"+thread2.count);

    }
}
class Lock{
    //判断是否需要被唤醒
    boolean needNofity = false;

}
class Thread1 extends Thread {
    private Lock lock;

    public Thread1(Lock lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        synchronized (lock){
            for (int i = 1; i < 1001; i++) {
                if(i % 2 == 0 && i % 3 == 0 && i % 5 == 0 && i % 7 ==0){
                    try {
                        System.out.println(i+"==>进入等待");
                        //告诉另一个线程需要被唤醒,唤醒一次就+1一次
                        lock.needNofity = true;
                        //自己的线程等待
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //唤醒另外一个线程
                lock.notify();
            }

        }
    }
}
class Thread2 extends Thread{
    private Lock lock;

    public Thread2(Lock lock) {
        this.lock = lock;
    }
    public int count = 0;
    @Override
    public void run() {
        //定义while循环、如果是true就循环
        while(true) {
            synchronized (lock) {
                //判断是否需要被唤醒
                if (lock.needNofity) {
                    //唤醒
                    lock.notify();
                    //唤醒一次就+1
                    System.out.println("唤醒:" + (++count) + "次");
                    //再把状态变成false,继续循环
                    lock.needNofity = false;
                }
                try {
                    //自己等待
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

六种线程状态详解 的相关文章

  • 如何从 Play WSClient 的字符串创建 WSResponse 对象

    文档 https www playframework com documentation 2 4 x JavaTestingWebServiceClients Mock the web service建议使用模拟Web服务测试基于WSCli
  • 将一种类型的对象声明为另一种类型的实例有什么好处? [复制]

    这个问题在这里已经有答案了 可能的重复 Base b2 new Child 是什么意思 表示 https stackoverflow com questions 4447924 what does base b2 new child sig
  • 如何使用 Maven Failsafe 插件运行 JUnit 5 集成测试?

    当我运行命令时 Maven Failsafe 插件找不到我的 JUnit 5 集成测试mvn clean failsafe integration test 尽管它可以找到文件 我有junit jupiter api and junit j
  • Java:线程“主”中的异常 java.lang.StringIndexOutOfBoundsException:字符串索引超出范围:

    我是初学者 谁能帮我弄清楚我们在做什么 我正在尝试读取字符串并将字符串的每个字符存储在数组中 import java util Scanner public class CoreMainDigitExtractor static Scann
  • Android WebView文件上传

    我正在开发一个 Android 应用程序 基本上它是一个WebView和一个进度条 Facebook 的移动网站 m facebook com 已加载到WebView 当我单击 选择文件 按钮上传图像时 没有任何反应 我已经尝试了所有的解决
  • 在 Java 中创建 T 的新实例

    在C 中 我们可以定义一个泛型class A
  • 从 HttpClient 3 转换为 4

    我已经成功地对所有内容进行了更改 但以下内容除外 HttpClient client HttpPost method client new DefaultHttpClient method new HttpPost url InputStr
  • 查找数组中的组合

    我在java中有一个像这样的二维数组 transmission communication tv television approach memorycode methodact 我需要获得所有组合 例如 transmission appr
  • 更改 JComboBox 中滚动条的大小

    有谁知道如何手动更改 jComboBox 中的滚动条大小 我已经尝试了一大堆东西 但没有任何效果 好吧 我明白了 您可以实现 PopUpMenuListener 并使用它 public void popupMenuWillBecomeVis
  • 使用 HTTPServletRequestWrapper 包装请求参数

    我有一个可以验证 授权 REST 调用的过滤器 该过滤器需要访问请求参数 因此我为此编写了一个自定义 HTTPServletRequestWrapper import java util Collections import java ut
  • 配置jmxremote时无法正常停止tomcat

    我添加了一个jmxremotecatalina bat中的配置 set JAVA OPTS Dcom sun management jmxremote port 9004 Dcom sun management jmxremote ssl
  • java swing:向 JTree 项目添加自定义图形按钮

    我想在 JTree 中的项目右侧添加一个带有小图标的附加按钮 这可以做到吗 如果是这样 怎么办 thanks Clamp 你在这方面成功了吗 我想做同样的事情 但很难让 JButton 响应用户 设置渲染器以显示按钮的过程很顺利 但所有鼠标
  • 如何检查日期字符串的有效性?

    在我的项目中 我需要检查日期字符串是否计算为正确的日期对象 我决定允许 yyyy MM dd 和日期格式 年 月 日 和 年 月 日 小时 分钟 我如何检查它们是否有效 我的代码为 1980 01 01 和一些奇怪的日期 如 3837 05
  • 在循环中按名称访问变量

    我正在开发一个 Android 项目 并且有很多可绘制对象 这些绘图的名称都类似于icon 0 png icon 1 png icon 100 png 我想将这些可绘制对象的所有资源 ID 添加到整数 ArrayList 中 对于那些不了解
  • Java和手动执行finalize

    如果我打电话finalize 在我的程序代码中的一个对象上 JVM当垃圾收集器处理这个对象时仍然再次运行该方法吗 这是一个大概的例子 MyObject m new MyObject m finalize m null System gc 是
  • 如何将库添加到 LIBGDX 项目的依赖项 gradle

    一切都在问题中 我已经尝试了在 SO 和其他网站中找到的所有答案 但没有运气 这就是我迄今为止尝试过的 adding compile fileTree dir lib include jar 到我的 build gradle adding
  • 如何清理 Runtime.exec() 中使用的用户输入?

    我需要通过命令行调用自定义脚本 这些脚本需要很少的参数并在 Linux 机器上调用 当前版本容易出现各种shell注入 如何清理用户给出的参数 参数包括登录名和路径 Unix 或 Windows 路径 用户应该能够输入任何可能的路径 该路径
  • Java 中的微分方程

    我正在尝试用java创建一个简单的SIR流行病模型模拟程序 基本上 SIR 由三个微分方程组定义 S t l t S t I t l t S t g t I t R t g t I t S 易感人群 I 感染人群 R 康复人群 l t c
  • @Embeddable 中的 @GenerateValue

    我已将实体的 id 分离到一个单独的 Embeddable 类中 该实体如下 Entity Table name users public class Users EmbeddedId private Users pk id private
  • 如何使用 Jest 从 ElasticSearch 获取索引列表

    我正在尝试使用 Jest 检索索引列表 但我只得到 Stats statistics new Stats Builder build result client execute statistics 如何从结果中检索索引列表 除了统计之外

随机推荐

  • python获取程序运行过程中所需要的时间

    使用python的过程中 需要得知程序从运行开始到结束所需要的时间 可以使用clock 的方法来实现 引入所需要的时间库 import datetime import time 程序计时器 启动计时器 start time clock 中间
  • conda 环境无法激活的问题

    项目场景 提示 这里简述项目相关背景 例如 项目场景 示例 通过蓝牙芯片 HC 05 与手机 APP 通信 每隔 5s 传输一批传感器数据 不是很大 安装anaconda3 pypcharm pycharm解释器使用anaconda3目录下
  • Dynamics 365 9.0 Version 新功能(1) 支持查找没有Opporunity的Account

    Dynamics 365 升级到9 0版本后 增强了高级查找中相关实体1 N关系的不包含数据的查询 这个功能虽然不太起眼 但是确实很多人期盼已久的 先来看下之前版本的高级查找 我以Accouts为示例 选择查询的相关实体是Opportuni
  • 4.tcp问题及进程

    1 tcp 问题 a 粘包 b 拆包 解决 1 1 解决方案 1 粘包 特殊字符方式 a 当时短连接的情况下 不用考虑粘包的情况 b 如果发送数据无结构 如文件传输 这样发送方只管发送 接收方只管接收存储就ok 也不用考虑粘包 c 如果双方
  • ccf-201412-3 集合竞价(详解)

    ccf 201412 3 集合竞价 详解 试题编号 201412 3 试题名称 集合竞价 时间限制 1 0s 内存限制 256 0MB 问题描述 问题描述 某股票交易所请你编写一个程序 根据开盘前客户提交的订单来确定某特定股票的开盘价和开盘
  • alive workers 数量为0的解决方案

    因为hostname显示的主机名与 etc hosts中的主机名不相同 所以都会导致无法连接slave 将集群的主机均实现hostname与 etc hosts名称一样 就解决了问题 如下所示
  • 捕获原点

    一 什么是捕获 即当某一种信号触发时 GTS 运动控制器能准确记录触发时刻轴的位置信息 二 捕获的方式 GTS 控制卡提供四种捕获方式 Home 捕获 Index 捕获 探针 Probe 捕获和 HSIO 捕获 1 Home捕获模式 GTS
  • vue3中使用第三方插件mitt实现任意组件通讯

    vue3中使用第三方插件mitt实现任意组件通讯 组件通讯是vue3组合式开发的核心之一 现在我在写代码时 一个组件的代码超过了200行 基本都会拆分组件 组件拆分后 组件之间的通讯就很重要 总结了一下 目前有这么几种组件通讯类型 父子通讯
  • Arduino基于ESP8266模块的TCP透传功能使用TCP透传协议连接移动onenet

    一 硬件资源 1 Arduion UNO R3 2 ESP8266WIFI模块 二 需要提前明确的知识点 1 ESP8266模块具有TCP透传功能 通过AT指令可以使得WIFI模块连接至相应的服务器 2 onenet具有多协议接入方式 例如
  • 网络流(入门)-概念

    相关概念介绍 这里的相关概念引用的是yxc大佬的讲解 在这里特别感谢yxc大佬的算法课 让我入了算法竞赛的门 1 1 流网络 G V E 特点 是一个有向图 且可以有环 不考虑反向边 即使有反向边 也可以通过加点来把一条反向边 变成两条单向
  • Candence学习篇(6)使用allegro绘制元器件的PCB封装

    文章目录 前言 一 确定引脚坐标位置 二 新建封装 2 1设置封装的大小 2 2 设置焊盘路径 三 绘制PCB封装 3 1参数设置 3 2放置边框矩形 3 3放置装配层 放置丝印层和1脚指示原点 总结 前言 前面我们讲了 Candence学
  • 一只兔子每三个月生兔子JAVA,兔子生兔子问题

    关于兔子生兔子的算法详解 有一对兔子 从出生后第3个月起每个月都生一对兔子 小兔 子长到第三个月后每个月又生一对兔子 假如兔子都不死 问每个月的兔子总数为多少 分析 第1个月 1对 第2个月 1对 第3个月 原来的1对 新生1对 2对 第4
  • 指针在函数中的传递,搞懂这两幅图指针基础就过关了

    a本身即是char 类型 所以 a是char 类型 strcpy 中里面的参数是地址 adf 前面应该要加 吧 printf输出的是数组 所以用a
  • Git安装操作流程(超超超级详细)

    一 前言 被迫投向程序媛的行列 一切都要白手起家 接下来就以初学者的视角手把手记录 git 教程 由于我体质特殊 过手的普通操作也总能有各类bug 因此教程也会不定期更新我的bug们 二 Git 下载及安装 1 Git 安装 首先去 Git
  • html jwt权限控制,SpringBoot+SpringSecurity+JWT实RESTfulAPI权限控制

    在整合jwt之前 我们首先要在SpringBoot中整合security的模块 来实现基于security的授权控制 用过security的人都知道 它的功能无比的强大比shiro还要强大 但是今天我就介绍security中关于权限控制和是
  • Linux基础与实操_韩顺平mooc知识点笔记

    Linux 目录 Linux 一 介绍 1 1目录结构 二 实操 2 1远程登陆 2 2 vi和vim 2 2 1 三种模式 2 2 2 快捷键 2 3 关机 重启 2 5 用户管理 2 5 1 用户家目录 2 5 2 添加用户 2 5 3
  • java入门到进阶书单

    入门 1 2年 初级 Head First Java 主要讲设计模式 这个是设计思想方面的 我之所以觉得它应该最早学 就是觉得这个对今后你看jdk tomcat源码 看第三方项目源码 以及一些大数据中间源码有所帮助 另外也有一本书叫 大话设
  • Matlab-矩阵

    目录 一 矩阵的操作 1 创建矩阵 1 建立简单矩阵 2 建立特殊矩阵 3 希尔伯特 Hilbert 矩阵 4 托普利兹 Toeplitz 矩阵 5 0 1间均匀分布的随机矩阵 6 标准正态分布随机矩阵 7 魔方矩阵 8 帕斯卡矩阵 9 范
  • IT中文技术站十大网站收藏

    1 CSDN www csdn net CSDN Chinese Software Developer Network 创立于1999年 是中国的IT社区和服务平台 为中国的软件开发者和IT从业者提供知识传播 职业发展 软件开发等全生命周期
  • 六种线程状态详解

    1 线程状态概述 线程从创建到运行到结束是一个线程的生命周期 当线程被创建到结束过程中 不是一直处于运行状态的 下面来介绍一下线程从运行到结束所有的状态 线程状态 导致状态发生条件 NEW 新建 线程刚被创建 没有启动 也就是还没调用sta