【Java多线程(2)】Thread常见方法和线程状态

news2024/9/21 2:39:50

目录

一、Thread类及常见方法

1. join() 等待一个线程

2. currentThread() 获取当前线程引用

3. sleep() 休眠当前线程

二、线程的状态

1. 线程的所有状态

2. 状态转移


一、Thread类及常见方法

接上文:多线程(1)icon-default.png?t=N7T8http://t.csdnimg.cn/wuphT

Thread类中还有一些要介绍的方法 。

1. join() 等待一个线程

有时,我们需要等待⼀个线程完成它的工作后,才能进行下一步的工作。例如,张三只有等李四转账成功,才决定是否收钱,这时我们需要⼀个⽅法明确等待线程的结束。

public class Demo6 {
    public static void main(String[] args) throws InterruptedException {
        //join() 等待一个线程
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("thread end");
        });

        t.start();

        //死等
        //t.join();    先打印 thread end  再打印 main end

        //最多等millis毫秒
        t.join(1000);
        System.out.println("main end");  //先打印 main end  再打印 thread end
    }
}

当在一个线程中调用另一个线程的 join() 方法时,当前线程会被阻塞,直到被调用的线程执行完成或超时。例如在上述代码中,调用 t.join() 表示 main 线程会等待 t 线程执行完成或超时,再执 行 main 线程。

  • 如果调用空参的 join() 方法,当前线程会一直被阻塞,直到被调用线程执行完成。
  • 如果调用有参的 join(long millis) 方法,当前线程会被阻塞指定的时间。如果指定时间内被调用线程执行完成,则结束阻塞状态,执行main线程;如果超出指定时间被调用线程没有执行完成,则main线程会继续执行,而被调用的线程仍然会继续执行直到完成。

因此,如果调用空参的 join() 方法,上述代码会先打印thread end,再打印 main end。如果调用有参的 join(long millis) 方法,由于main线程只等待1秒,而t线程会睡眠2秒,等待时间结束后t线程仍在睡眠,所以会先打印main end,再打印thread end。

2. currentThread() 获取当前线程引用

这个方法在前面就使用过了。

currentThread()Thread 类的静态方法,用于获取当前正在执行的线程对象。当调用 Thread.currentThread() 方法时,会返回表示当前线程的 Thread 对象。

使用场景:

  1. 在使用匿名内部类或者Lambda表达式中,由于还没有创建线程对象,我们就可以用currentThread()方法获取当前线程引用。
  2. 创建线程的第二种方式中,由于 Runnable 接口本身并不包含与线程相关的方法,而只有一个 run() 方法。因此,在实现 Runnable 接口时,需要将其实现类传递给 Thread 对象的构造函数,然后通过 Thread 对象来创建和管理线程。所以就可以通过 Thread.currentThread() 方法来获取当前线程的引用。

而用创建线程的第一种方式中,我们是通过继承Thread类创建线程,就可以直接用this获取当前线程的引用了。

public class Demo7 {
    public static void main(String[] args) {
        //currentThread() 获取当前线程引用
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
    }
}

3. sleep() 休眠当前线程

这也是我们前面就一直在使用的方法。

sleep() 方法是 Thread 类的一个静态方法,它让当前线程暂停执行指定的时间。在调用 sleep() 方法后,当前线程会暂时放弃 CPU 的执行权,进入阻塞状态,让其他线程有机会执行。一旦休眠时间结束,线程就会重新进入就绪状态,等待CPU调度执行。

注意事项:

  • 在理论上,调用 Thread.sleep() 方法后,线程会暂停执行指定的时间,但实际休眠时间可能会略微超过设置的休眠时间。这是由于操作系统调度和线程切换所带来的额外开销和延迟。
  • 具体来说,Thread.sleep() 方法是通过将当前线程置于休眠状态来实现延迟,但并不保证在精确的时间后唤醒线程。操作系统和 JVM 在处理线程睡眠时可能会引入一些额外的延迟,比如线程调度、上下文切换等。因此,实际休眠时间可能会略微超过设置的休眠时间,但通常不会有太大的偏差。

也就是说,当休眠时间到了之后,线程从阻塞状态恢复到运行状态,但不代表线程就能立即去CPU上执行。

public class Demo8 {
    public static void main(String[] args) throws InterruptedException {
        long prevTime = System.currentTimeMillis();
        Thread.sleep(1000);
        long currTime = System.currentTimeMillis();
        System.out.println("实际休眠时间:" + (currTime - prevTime));
    }
}

在这段代码中,首先记录了调用 Thread.sleep(1000) 前的时间戳 prevTime,然后让当前线程休眠1秒钟(1000毫秒),接着再获取休眠后的时间戳 currTime,最后计算并输出两个时间戳之间的差值,即实际休眠时间。

二、线程的状态

1. 线程的所有状态

线程的状态是⼀个枚举类型 Thread.State

 而 RUNNABLE 状态又可以分成两种状态:1.正在工作中(RUNNING),2.即将开始工作(READY)。

2. 状态转移

  1. 新建 -> 就绪:当调用线程的 start() 方法启动线程时,线程从新建状态转移到就绪状态。
  2. 就绪 -> 运行:当线程获取到 CPU 时间片开始执行时,线程从就绪状态转移到运行状态。
  3. 运行 -> 阻塞:当线程需要等待某个条件满足时,如调用 sleep() 方法或者等待 I/O 操作完成时,线程从运行状态转移到阻塞状态。
  4. 运行 -> 终止:线程执行完任务或者出现异常导致线程结束时,线程从运行状态转移到终止状态。
  5. 阻塞 -> 就绪:当线程等待的条件满足或者资源释放后,线程从阻塞状态转移到就绪状态。
  6. 就绪 -> 终止:线程执行完任务或者出现异常导致线程结束时,线程从就绪状态转移到终止状态。
通过一个示例来看NEW、RUNNABLE和TERMINATED状态的转换:
public class Demo9 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        //NEW: 安排了⼯作, 还未开始⾏动
        System.out.println(t.getState());

        t.start();

        //RUNNABLE: 可⼯作的. ⼜可以分成正在⼯作中(RUNNING)和即将开始⼯作(READY).
        System.out.println(t.getState());

        t.join(); //让main线程等待t线程执行完毕
        //TERMINATED: ⼯作完成了.
        System.out.println(t.getState());
    }
}

1. 已经创建了线程对象,但还未开启线程,处于NEW状态。

2. 开启线程,线程处于执行中,是RUNNABLE状态。

3. t线程执行完成,为TERMINATED状态。

最后看下另外的三种状态(需要使用 jconsole 工具和后续内容锁): 

  1. 阻塞(Blocked):线程被挂起,等待某个条件满足或者等待其他资源释放。比如调用 sleep()wait() 方法或者等待 I/O 操作完成时会进入阻塞状态。
  2. 等待(Waiting):线程进入等待状态,等待其他线程通知唤醒。比如调用 Object.wait()Thread.join() 或者 LockSupport.park() 方法时会进入等待状态。
  3. 超时等待(Timed Waiting):与等待状态类似,不同之处在于可以设置一个超时时间,在超时时间到达前等待或者在接收到通知前等待。比如调用 Thread.sleep()Object.wait(timeout) 或者 Thread.join(timeout) 方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1546393.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker 【安装MongoDB】

文章目录 前言一、安装二、使用1. 通过权限认证的方式登入2. 基础操作 前言 MongoDB是一个非关系型数据库,它主要的应用场景有这些 相比mysql,MongoDB没有事务,索引之类的东西。最小单位是文档。 可能有人说,为什么这个场景我要…

【无标题】如何使用 MuLogin 设置代理

如何使用 MuLogin 设置代理 使用 MuLogin 浏览器设置我们的代理,轻松管理多个社交媒体或电子商务帐户。 什么是MuLogin? MuLogin 是一款虚拟反检测浏览器,使用户能够管理多个电子商务、社交媒体和广告帐户,而无需验证码或 IP 禁…

canvas画带透明度的直线和涂鸦

提示&#xff1a;canvas画线 文章目录 前言一、带透明度的直线和涂鸦总结 前言 一、带透明度的直线和涂鸦 test.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content…

Chrome浏览器修改网页内容

方法一&#xff1a;使用开发者工具 在Chrome浏览器中打开要修改的网页。按下F12键打开开发者工具。在开发者工具窗口中&#xff0c;找到“Elements”标签页。在“Elements”标签页中&#xff0c;找到要修改的网页元素。双击要修改的网页元素&#xff0c;即可进行编辑。 方法二…

轻松掌握:使用 API 接口自动缩短网址的秘诀

在互联网的世界里&#xff0c;网址缩短已经成为了一种时尚和必要。长而复杂的网址不仅难以记忆&#xff0c;还可能让人望而却步。但是&#xff0c;现在有了 API 接口&#xff0c;我们可以轻松地将网址自动缩短&#xff0c;让分享变得更加简单和高效&#xff01;本文将以具体例子…

Protocol Buffers设计要点

概述 一种开源跨平台的序列化结构化数据的协议。可用于存储数据或在网络上进行数据通信。它提供了用于描述数据结构的接口描述语言&#xff08;IDL&#xff09;&#xff0c;也提供了根据 IDL 产生代码的程序工具。Protocol Buffers的设计目标是简单和性能&#xff0c;所以与 XM…

vue脚手架创建项目:账号登录(利用element-ui快速开发)(取消eslint强制格式)(修改端口号)

新手看不懂&#xff0c;老手不用看系列 文章目录 一、准备工作1.1 取消强制格式检查1.2 导入依赖&#xff0c;注册依赖 二、去element-ui官网找样式写Login组件2.1 引用局部组件2.2 运行项目 三、看一下发现没问题&#xff0c;开始修改前端的代码四、修改端口号4.1 修改后端端口…

Redis 之死:Garantia Data 如何策划了开源史上最大劫案?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Temple of Doom靶场nodejs获取shellss-manager漏洞tcpdump提权

下载链接&#xff1a; Temple of Doom: 1 ~ VulnHub 下载完成后直接在vxbox中导入即可&#xff0c;网络链接模式根据自身情况而定&#xff08;我采用的桥接模式&#xff09; 正文&#xff1a; 先用nmap进行扫描靶机ip nmap -sn 192.168.1.1/24 对192.168.1.5进行端口探测&a…

Spring学习——什么是循环依赖及其解决方式

文章目录 前言一、什么是循环依赖二、解决思路1、循环依赖分类2、对象初始化步骤及对象分类3、spring是如何解决的4、图解5、三级缓存1、区别2、ObjectFactory是什么 三、源码debug1、spring创建对象过程1、dubug第一步——找到getBean2、dubug第二步——getBean与doGetBean3、…

基于AT89C51单片机的智能交通灯设计

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/89035863?spm1001.2014.3001.5503 1绪 论 1.1课题研究背景 交通是城市经济活动的命脉&#xff0c;对城市经济发展、人民生活水平的提高起着十分重要的作用。城市交…

用 C++ 编码架构图的最佳用例

统一建模语言&#xff08;UML&#xff09;&#xff0c;作为一种实际应用的语言标准&#xff0c;借助一系列架构图呈现建模软件系统。UML 的出现鼓励了自动化软件工具的开发&#xff0c;有助于自动代码生成。UML 图面向对象系统和软件工具&#xff0c;将静态结构和动态行为以可视…

如何统计代码量

工具&#xff1a; cloc 下载地址&#xff1a; Releases AlDanial/cloc GitHub 使用方法&#xff1a;

2024.3.26

实现闹钟 weiget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTimer> #include<QTime> #include<QTimerEvent> #include<QString> #include<QtTextToSpeech> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } Q…

力扣● 503.下一个更大元素II ● 42. 接雨水

503.下一个更大元素II 与496.下一个更大元素 I的不同是要循环地搜索元素的下一个更大的数。那么主要是对于遍历结束后&#xff0c;单调栈里面剩下的那些元素。 如果直接把两个数组拼接在一起&#xff0c;然后使用单调栈求下一个最大值就可以。 代码实现的话&#xff0c;不用直…

ubuntu22.04配置Azure Kinect DK深度相机

一.安装SDK 今天我来配置一下微软公司的Azure Kinect DK深度相机,以前在ubuntu18.04上配置过,因为官方说唯一支持linux版本是18.04,所以在18.04中配置还算顺利 but这不代表不可以在更高版本的ubuntu中使用,只不过需要自己去多配置一些东西 apt 源安装 更新源: c…

上海企业必应bing国内广告推广如何开户?

随着数字化营销时代的深入发展&#xff0c;搜索引擎广告已成为众多企业提升品牌知名度和促进产品销售的重要手段之一。在国内市场&#xff0c;微软必应&#xff08;Bing&#xff09;搜索广告以其精准定位与高价值用户群赢得了众多企业的青睐。对于位于上海地区的企业来说&#…

蓝桥杯:Python基础学习一

目录 一、遍历列表 1.使用for 循环和 enumerate()函数实现 2.案例代码 二、对列表进行统计和计算 1.统计数值列表的元素和 2.案例代码 三、对列表进行排序 1.使用列表对象的sort()方法 2.使用内置的 sorted()函数实现 四、列表推导式 1.从列表中选择符合条件的元素组…

flask_restful结合蓝图使用

在蓝图中&#xff0c;如果使用 Flask_RESTful &#xff0c; 创建 Api 对象的时候&#xff0c;传入蓝图对象即可&#xff0c;不再是传入 app 对象 /user/__init__.py from flask.blueprints import Blueprintuser_bp Blueprint(user,__name__)from user import views /user…

泛型编程的启蒙之旅

个人主页&#xff1a;日刷百题 系列专栏&#xff1a;〖C/C小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 &#x1f30e;欢迎各位→点赞&#x1f44d;收藏⭐️留言&#x1f4dd; ​ ​ 讲模板之前呢&#xff0c;我们先来谈谈泛型编程&#xff1a; 泛型编程&#xff1a;编写与类…