当前位置: 首页 > news >正文

Thread类及线程的核心操作

一. Thread类的常见构造方法

1. Thread()

Thread类无参的构造方法, 用于创建Thread类的实例对象.

2. Thread(String name)

带一个参数的Thread类构造方法, 创建一个线程对象, 并给其命名.

[注]: 如果不专门给线程命名, 那么线程默认的名字就是Thread-0, Thread-1, Thread-2 ...... , 给线程取名字, 不会影响到线程的执行效果, 为线程取一个合适的名字, 有利于调试程序.

3. Thread(Runnable target)

带一个参数的Thread类构造方法, 使用Runnable对象来创建线程对象.

4. Thread(Runnable target, String name) 

带两个参数的Thread类构造方法, 使用Runnable对象来创建一个线程对象, 并给其命名.

5. Thread(ThreadGroup group, Runnable target)

[了解] 带两个参数的Thread类构造方法, 使用Runnable对象来创建线程, 并将线程分成线程组. 设置线程组是为了方便统一设置线程的一些属性, 现在实际开发中很少使用线程组, 而是使用"线程池". 所以, 该构造方法我们了解即可.

二. Thread类几个常见属性和方法

1. Id

ID是Thread对象的身份标识, 是JVM自动分配的, 不能手动设置. 是Thread对象的身份标识. 使用getId()方法可以获取Thread对象的ID.

[注意]: ID是Thread对象的身份标识, 而不是线程的身份标识!!!  通常情况下, 一个Thread对象应该是对应到系统内核的一个线程上的, 但是也有可能Thread对象创建好了, 却没有启动这个线程, 那么此时系统内核就没有这个线程. 或者线程已经销毁了, 但是Thread对象还在.

2. name

线程名称, 使用getName()方法可以获取线程的name.

3. state

线程状态, 是JVM自动分配的, 不能手动设置. "就绪/阻塞 ... 都是进程的状态".

4. priority

进程优先级.

5. isDaemon()

是否为后台线程. (一个线程如果没有指定, 那么默认它是前台线程)

这里我们要辨析一下, 什么是"后台线程", 什么是"前台线程", 以及这两者之间有什么区别.

(1) 前台线程

        概念: 如果某线程在执行过程中能够控制线程结束, 那么这个线程就是前台线程.

        特点: 前台线程宣布进程结束, 此时进程立即结束, 后台线程也会随之结束.  前台线程没有宣布结束, 后台线程即使结束了也不影响进程继续执行.

(2) 后台线程

        概念: 如果某个线程在执行过程中不能控制线程结束, 那么这个线程就是后台线程. (例如: 虽然某个后台线程正在执行, 但是此时进程要结束了, 那么后台线程也会随之结束.)

        特点: 进程要结束(前台线程要结束), 后台线程无力阻止, 也会随之结束. 后台线程先结束了, 也不影响进程的继续执行(其他前台线程的继续执行).

通过上述分析, 我们可以理解为, 前台线程就是"话事人", 而后台线程就是一个"小透明". 前台线程的一举一动都影响着整个进程的状态, 而后台线程是否结束则对整个进程丝毫没有影响.

6. isAlive()

是否存活.

这里isAlive()表示的是内核中的线程是否存活. 为true表示内核中的线程存在, 为false表示内核中的线程不存在了.

7. isInterrupted()

线程是否被中断.

我们可以通过代码演示一下上述几个属性方法.

public class Demo4 {public static void main(String[] args) {Thread t = new Thread(new Runnable(){@Overridepublic void run() {for (int i = 0; i < 3; i++){System.out.println("hello thread");}}});System.out.println(t.getId());//获取线程IDSystem.out.println(t.getName());//获取线程名称System.out.println(t.getState());//获取线程状态System.out.println(t.getPriority());//获取线程优先级System.out.println(t.isDaemon());//是否为后台线程System.out.println(t.isAlive());//是否存活System.out.println(t.isInterrupted());//是否被终止t.start();}
}

代码运行结果如下:

 

三. 线程的几个核心操作

1. 启动一个线程 -- start()

start() 方法由一个线程对象调用, 表示启动该线程. 一旦start()方法执行完毕, 新线程就会立即开始执行. 调用start() 的线程也会继续执行.

例如: 我们在main方法中用t调用了start()方法, 相当于启动了一个新线程t, 从此刻开始, 线程"兵分两路", 一路继续执行main线程, 一路执行新的t线程, 两个线程并发执行. 示意图如下:

[注意]: 由于一个Thread对象只能对应内核中的一个线程, 所以一个Thread对象只能调用一次start()方法(只能启动一次线程). 如果多次调用start()方法, 那么就会报错.

2. 终止一个线程 

例如, 我们现在有A, B两个线程. B正在运行, 而A想要B结束. 此时A要做的就是让B把它的run方法执行完, B线程自然就结束了. (注:  这里A不会直接强制终止B)

我们举如下示例: 设置一个isRunning变量. isRunning为true, 则表示t线程在运行; isRunning为false, 则表明线程结束.

public class Demo7 {private static boolean isRunning = true;public static void main(String[] args) {// boolean isRunning = true;Thread t = new Thread(() -> {while (isRunning) {   // 如果t线程运行, 则执行while中的任务System.out.println("hello thread");try {Thread.sleep(1000);  // 每隔1000ms打印一次"hello thread"} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("t 线程结束");});t.start();try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}// 3s 之后, 主线程修改 isRunning 的值, 从而通知 t 结束.System.out.println("控制 t 线程结束");isRunning = false; //将isRunning置为false, 表示控制t线程结束.}
}

这段代码运行结果如下:

 

 

当然, 由于线程的终止是一个"比较温和"的操作, 所以, 当A线程让B线程结束时, B可以自行选择: 立即结束 / 执行完当前任务再结束 / 无视A, 继续执行. 

public class Demo8 {public static void main(String[] args) {Thread t = new Thread(() -> {// t.isInterrupted();Thread currentThread = Thread.currentThread(); //currentThread是Thread类中的一个静态方法, 表示获取当前线程的引用while (!currentThread.isInterrupted()) { //isInterrupted是Thread类中的一个成员方法,用于检查线程是否已被中断.初始值是false, 表示线程没有被中断.System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// throw new RuntimeException(e);// e.printStackTrace();// balabala 写一些其他的逻辑之后, 再 break//break;}}});t.start();try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}t.interrupt();}
}

 interrupt方法, 能够设置标志位, 也能唤醒sleep等阻塞方法; sleep方法被唤醒后, 又能清除标志位.

上述代码中, 我们通过在catch中进行不同的操作, 可以实现不同的目的. 

(1) 无视A的命令, 继续执行: catch中什么都不做.

(2) 稍后结束线程: 线执行一系列收尾工作,在break/return.

(3) 立即结束线程: 直接break/return.

3. 等待一个线程 -- join

我们知道, 多个线程的并发执行, 实质上是一个"随机调度, 抢占式执行"的方式. 所以我们程序员并不能指定哪个线程先执行, 哪个线程后执行. 但是我们可以通过让一个线程等待另一个线程来控制哪个线程先结束, 哪个线程后结束. 这里的线程等待, 就要用到 join方法. 

例如: 现在计算机上正在执行两个线程a和b, 我们现在想要让a线程等待b线程执行完, a才能继续维往下执行.

基本语法是:

b.join ();

意思就是让a线程等待b线程执行结束, a再继续往下执行.

public class Demo10 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {for (int i = 0; i < 3; i++) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("thread end");});t.start();//启动t线程for (int i = 0; i < 5; i++) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("开始等待t线程");t.join(); // 此处在main线程中加一个t.join(), 表示main线程等待t线程执行结束后才能结束System.out.println("t线程执行结束, 等待完成");System.out.println("继续执行main线程后面的部分");System.out.println("main线程执行结束");}
}

  此处在main线程中加一个t.join(), 就表示main线程等待t线程执行完成之后继续才能执行main线程后面的任务.

那么我们可不可以让t线程等待main线程呢? 那当然也是可以的~

public class Demo9 {public static void main(String[] args) throws InterruptedException {Thread mainThread = Thread.currentThread();Thread t = new Thread(() -> {System.out.println("t线程开始等待");try {mainThread.join(); //在t线程中插入一个mainThread.join(), 表示让t线程等待main线程.} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("main线程执行结束, t线程结束等待, 准备开始执行t线程后面的内容");for (int i = 0; i < 3; i++) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t线程执行结束");});t.start();for (int i = 0; i < 5; i++) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("main线程执行结束");}
}

 ​​​那么此时的t线程就必须等main线程的任务全部执行完才能执行t线程后面的任务了. 上述代码执行结果如下: 

 

好, 既然两个线程之间可以相互等待, 那么一个线程能不能等待多个线程呢? 答案也是可以的~~

public class Demo11 {public static void main(String[] args) throws InterruptedException {Thread t2 = new Thread(() -> {for (int i = 0; i < 4; i++) {System.out.println("t2");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});Thread t1 = new Thread(() -> {for (int i = 0; i < 3; i++) {System.out.println("t1");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();t2.start();System.out.println("开始等待t1, t2");t1.join();t2.join();System.out.println("t1, t2执行完毕, main线程结束等待t1, t2");System.out.println("继续执行main后面的任务");System.out.println("main线程执行结束");}
}

上述代码执行结果如下:

 

注意: join()的作用是 保证被等待的线程能够先结束. 如果开始等待的时候, 发现被等待的线程已经结束了, 那么就不需要再等了. 

上述使用的join( ) 不带参数, 表示"死等", 只要被等待的线程不执行完毕, 就会持续阻塞, 不会继续往下执行. 但是这样的等待方式显然是不好的, 所以java还提供了一种带参数的形式: join( long millis) 参数表示最多等待millis毫秒, 如果在这段时间内等待还没有结束, 那么就不会再等了.

4. 获取当前线程的引用

使用Thread类的currentThread()方法, 表示获取当前线程的引用.

例如, 获取main线程的引用:

 在任何线程中, 在任何需要的时候, 都可以通过此方法, 拿到当前线程的引用.

5. 休眠当前线程

通过Thread类中的sleep()方法, 休眠当前线程. 某线程执行sleep(), 就会让该线程处于阻塞等待状态, 此时这个线程不参与CPU调度, 从而把CPU资源让出来, 给别人使用.

使用sleep()可以解决实际开发中某些线程CPU占用率过高的问题.

好的, 以上就是本篇博客的全部内容啦, 如果喜欢小编的文章, 可以点赞,评论,收藏~

相关文章:

Thread类及线程的核心操作

一. Thread类的常见构造方法 1. Thread() Thread类无参的构造方法, 用于创建Thread类的实例对象. 2. Thread(String name) 带一个参数的Thread类构造方法, 创建一个线程对象, 并给其命名. [注]: 如果不专门给线程命名, 那么线程默认的名字就是Thread-0, Thread-1, Thread-…...

算法|牛客网华为机试11-20C++

牛客网华为机试 上篇&#xff1a;算法|牛客网华为机试1-10C 文章目录 HJ11 数字颠倒HJ12 字符串反转HJ13 句子逆序HJ14 字符串排序HJ15 求int型正整数在内存中存储时1的个数HJ16 购物单HJ17 坐标移动HJ18 识别有效的IP地址和掩码并进行分类统计HJ19 简单错误记录HJ20 密码验证…...

OpenAI低调发布多智能体工具Swarm:让多个智能体协同工作!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…...

性能之光 年度电竞性能旗舰iQOO 13发布

2024年10月30日&#xff0c;被定义为“性能之光”的年度电竞性能旗舰——iQOO 13正式发布&#xff0c;售价3999元起。iQOO 13作为iQOO 品牌在性能上的又一次深入探索&#xff0c;它像是一束光&#xff0c;引领行业不断拉高性能上限&#xff0c;让用户看到更多的可能性。 iQOO …...

如何避免因不熟悉数据保护法规而受损

在当今数字化时代&#xff0c;数据保护法规的遵守对于企业至关重要。不熟悉新的数据保护法规会导致法律风险增加、财务损失、声誉受损、客户信任下降等多方面的负面影响。其中&#xff0c;法律风险增加尤为严重&#xff0c;因为不符合规定可能引发高额罚款和法律诉讼。企业若未…...

LLaMA Factory 核心原理讲解

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于大模型算法的研究与应用。曾担任百度千帆大模型比赛、BPAA算法大赛评委,编写微软OpenAI考试认证指导手册。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。授权多项发明专利。对机器学…...

Java题集练习5

Java题集练习5&#xff08;集合&#xff09; 1.三种集合差别&#xff0c;集合类都是什么&#xff0c;数据结构是什么&#xff0c;都什么时候用 三者关系 Set集合 Set接口是Collection接口的一个子接口是无序的&#xff0c;set中不包含重复的元素&#xff0c;也就是说set中不…...

操作系统学习笔记-2.3哲学家和管程问题

哲学家问题 问题描述 假设有五位哲学家围坐在一张圆桌旁&#xff0c;每位哲学家面前放有一盘意大利面&#xff0c;他们各自间隔放置一根叉子。哲学家的行为分为“思考”和“进餐”两种状态。为了进餐&#xff0c;哲学家需要同时拿起左手边和右手边的两根叉子。用餐结束后&…...

2023年信息安全工程师摸底测试卷

目录 1.密码算法 2.等级保护 3.密码学 4.安全评估 5.网络安全控制技术 6.恶意代码 7.身份认证 8.资产管理 9.密码分类 10.被动攻击 11.商用密码服务​编辑 12.超文本传输协议 13.数字水印技术 14.信息系统安全设计 15.重放攻击 16.信息资产保护 17.身份认证 …...

ReactOS系统中平衡二叉树。给定地址超导其所属区块MmFindRegion()

系列文章目录 PMM_REGION NTAPI MmFindRegion( PVOID BaseAddress, PLIST_ENTRY RegionListHead, PVOID Address, PVOID* RegionBaseAddress ); 宏函数 //给定地址找到其中所属区块 #define CONTAINING_RECORD(address,type,field) ((type FAR *\(PCHAR)(address)-(PCHAR)(&…...

基于TESSY的单元测试与分类树方法深入解析

在现代软件开发中,单元测试是确保软件质量和可靠性的关键步骤之一。特别是对于嵌入式软件,由于其应用环境的特殊性和高安全性要求,单元测试显得尤为重要。本文将基于《TESSY 用户手册》的内容,详细介绍如何使用TESSY 进行单元测试,并深入探讨分类树方法(Classification T…...

整理了一些大模型的课程,非常详细,大模型零基础入门到精通,收藏我这一篇就够了

目前有多个科普类的大模型课程&#xff0c;这些课程涵盖了从基础理论到实际应用的各个方面。以下是一些主要的科普类大模型课程&#xff1a;复旦大学“大模型开发与赋能”专题讲习班&#xff1a;由复旦大学计算机学院邱锡鹏教授带来的《大模型科普讲解》课程&#xff0c;通过深…...

区块链国赛题目--食品溯源(模块三)

区块链国赛题目–食品溯源(模块三) 任务 3-1:区块链应用前端功能开发 1.请基于前端系统的开发模板,在登录组件 login.js、组件管理文件components.js 中添加对应的逻辑代码,实现对前端的角色选择功能,并测试功 能完整性,示例页面如下: 具体要求如下: (1)有明…...

【Searxng】Searxng docker 安装

SearXNG将用户的查询请求分发至多个支持的搜索引擎&#xff0c;并收集返回的结果进行汇总处理。在这个过程中&#xff0c;它通过内置的过滤器功能屏蔽广告和其他不相关内容&#xff0c;确保搜索结果的纯净度。 一键部署 docker run \--name searxng \-p ????:8080 \-v ~/s…...

Java Lock/AQS ReentrantLock 源码

前言 相关系列 《Java & Lock & 目录》&#xff08;持续更新&#xff09;《Java & AQS & 目录》&#xff08;持续更新&#xff09;《Java & Lock/AQS & ReentrantLock & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Jav…...

魔法伤害--是谁偷走了我的0

起因&#xff1a;需要迁移数据进行数据更新&#xff0c;使用pandasorcal进行数据处理以及库迁移 首先把数据导出为xls格式数据文件&#xff0c;使用python import pandas as pdnew_obj pd.read_excel(ne,dtype{DAY: str, MONTH: str}) 原有导出数据格式为&#xff1a; 使用…...

【ArcGIS Pro实操第4期】绘制三维地图

【ArcGIS Pro实操第4期】绘制三维地图 ArcGIS Pro绘制三维地图-以DEM高程为例参考 如何使用ArcGIS Pro将栅格数据用三维的形式进行表达&#xff1f;在ArcGIS里可以使用ArcScene来实现&#xff0c;ArcGIS Pro实现原理跟ArcScene一致。由于Esri未来将不再对ArcGIS更新&#xff0c…...

Vuestic 整理使用

简单示例 1. 条件渲染 2. 列表渲染 3. 组件插槽 4. 插值语法 5. 前后端路由的区别(还是转一下,可以减少代码量)SFC 构建 … … Okay&#xff0c;可以干活了&#xff0c;通顺 数据表的操作更加简化了 数据类别通过后端路由区别,但是还得由前端路由转一下 简单了许多呀,上脚手…...

学习伊圣雨老师的 epoll 编程

&#xff08;1&#xff09;书里提出了疑问&#xff0c;epoll 函数的工作方式&#xff0c;区分为水平触发与边缘触发 &#xff1a; &#xff08;2&#xff09; 谢谢...

详细了解C++11(1)

大家好呀&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流哦 本文由&#xff1a;残念ing原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&#xff0c;欢迎各…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂&#xff0c;正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...