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++
牛客网华为机试 上篇:算法|牛客网华为机试1-10C 文章目录 HJ11 数字颠倒HJ12 字符串反转HJ13 句子逆序HJ14 字符串排序HJ15 求int型正整数在内存中存储时1的个数HJ16 购物单HJ17 坐标移动HJ18 识别有效的IP地址和掩码并进行分类统计HJ19 简单错误记录HJ20 密码验证…...
OpenAI低调发布多智能体工具Swarm:让多个智能体协同工作!
大家好,我是木易,一个持续关注AI领域的互联网技术产品经理,国内Top2本科,美国Top10 CS研究生,MBA。我坚信AI是普通人变强的“外挂”,专注于分享AI全维度知识,包括但不限于AI科普,AI工…...
性能之光 年度电竞性能旗舰iQOO 13发布
2024年10月30日,被定义为“性能之光”的年度电竞性能旗舰——iQOO 13正式发布,售价3999元起。iQOO 13作为iQOO 品牌在性能上的又一次深入探索,它像是一束光,引领行业不断拉高性能上限,让用户看到更多的可能性。 iQOO …...
如何避免因不熟悉数据保护法规而受损
在当今数字化时代,数据保护法规的遵守对于企业至关重要。不熟悉新的数据保护法规会导致法律风险增加、财务损失、声誉受损、客户信任下降等多方面的负面影响。其中,法律风险增加尤为严重,因为不符合规定可能引发高额罚款和法律诉讼。企业若未…...
LLaMA Factory 核心原理讲解
大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于大模型算法的研究与应用。曾担任百度千帆大模型比赛、BPAA算法大赛评委,编写微软OpenAI考试认证指导手册。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。授权多项发明专利。对机器学…...
Java题集练习5
Java题集练习5(集合) 1.三种集合差别,集合类都是什么,数据结构是什么,都什么时候用 三者关系 Set集合 Set接口是Collection接口的一个子接口是无序的,set中不包含重复的元素,也就是说set中不…...
操作系统学习笔记-2.3哲学家和管程问题
哲学家问题 问题描述 假设有五位哲学家围坐在一张圆桌旁,每位哲学家面前放有一盘意大利面,他们各自间隔放置一根叉子。哲学家的行为分为“思考”和“进餐”两种状态。为了进餐,哲学家需要同时拿起左手边和右手边的两根叉子。用餐结束后&…...
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…...
整理了一些大模型的课程,非常详细,大模型零基础入门到精通,收藏我这一篇就够了
目前有多个科普类的大模型课程,这些课程涵盖了从基础理论到实际应用的各个方面。以下是一些主要的科普类大模型课程:复旦大学“大模型开发与赋能”专题讲习班:由复旦大学计算机学院邱锡鹏教授带来的《大模型科普讲解》课程,通过深…...
区块链国赛题目--食品溯源(模块三)
区块链国赛题目–食品溯源(模块三) 任务 3-1:区块链应用前端功能开发 1.请基于前端系统的开发模板,在登录组件 login.js、组件管理文件components.js 中添加对应的逻辑代码,实现对前端的角色选择功能,并测试功 能完整性,示例页面如下: 具体要求如下: (1)有明…...
【Searxng】Searxng docker 安装
SearXNG将用户的查询请求分发至多个支持的搜索引擎,并收集返回的结果进行汇总处理。在这个过程中,它通过内置的过滤器功能屏蔽广告和其他不相关内容,确保搜索结果的纯净度。 一键部署 docker run \--name searxng \-p ????:8080 \-v ~/s…...
Java Lock/AQS ReentrantLock 源码
前言 相关系列 《Java & Lock & 目录》(持续更新)《Java & AQS & 目录》(持续更新)《Java & Lock/AQS & ReentrantLock & 源码》(学习过程/多有漏误/仅作参考/不再更新)《Jav…...
魔法伤害--是谁偷走了我的0
起因:需要迁移数据进行数据更新,使用pandasorcal进行数据处理以及库迁移 首先把数据导出为xls格式数据文件,使用python import pandas as pdnew_obj pd.read_excel(ne,dtype{DAY: str, MONTH: str}) 原有导出数据格式为: 使用…...
【ArcGIS Pro实操第4期】绘制三维地图
【ArcGIS Pro实操第4期】绘制三维地图 ArcGIS Pro绘制三维地图-以DEM高程为例参考 如何使用ArcGIS Pro将栅格数据用三维的形式进行表达?在ArcGIS里可以使用ArcScene来实现,ArcGIS Pro实现原理跟ArcScene一致。由于Esri未来将不再对ArcGIS更新,…...
Vuestic 整理使用
简单示例 1. 条件渲染 2. 列表渲染 3. 组件插槽 4. 插值语法 5. 前后端路由的区别(还是转一下,可以减少代码量)SFC 构建 … … Okay,可以干活了,通顺 数据表的操作更加简化了 数据类别通过后端路由区别,但是还得由前端路由转一下 简单了许多呀,上脚手…...
学习伊圣雨老师的 epoll 编程
(1)书里提出了疑问,epoll 函数的工作方式,区分为水平触发与边缘触发 : (2) 谢谢...
详细了解C++11(1)
大家好呀,我是残念,希望在你看完之后,能对你有所帮助,有什么不足请指正!共同学习交流哦 本文由:残念ing原创CSDN首发,如需要转载请通知 个人主页:残念ing-CSDN博客,欢迎各…...
ITA的去锅盖处理流程
一、说明 锅盖是什么 锅盖的类型有哪些 二、去锅盖处理流程 去锅盖算法首先需要采集一份锅盖模板数据,该模板数据用户可以自定义保存,方便后面的开机重启直接导入使用。去锅盖处理包含两个历程:保存锅盖模板;去锅盖处理。 保存锅盖模板: ( 1 ) 打开采集锅盖模板开关。…...
日志管理系统的系统目标是什么?
在网络安全、数据管理、故障排查等领域,日志都被广泛使用并需要进行有效的管理与分析。因此,日志管理系统的系统目标显得尤为重要,如以下几方面。 1、确保数据的安全性及完整性 在企业和组织的日常运营中,各类信息数据都会通过系统…...
uniapp 底部导航栏tabBar设置后不显示的问题——已解决
uniapp 底部导航栏tabBar设置后不显示的问题——已解决 网上找了一堆解决办法,挨个对着试吧 解决办法一:tabBar里的list第一项和page中的第一项要相同,确实就能显示了。但是问题来了,page中的第一项是入口页,那就意味…...
JVM 类加载器
字节码的结构 魔数u4 cafe babe 版本u4 52 java8 常量池计数器u2 从1开始,0索引留给不需要的情况 常量池 表 #1 -> #计数器-1 类标识符 u2 public final abstrat class annotion interface 之类 类索引u2 名字 父类索引u2 父类名字 接口计数器 u2 接口数…...
《C++长时间运行程序:驯服内存膨胀的“怪兽”》
在 C编程的世界里,当我们编写长时间运行的程序时,内存膨胀问题就像一个隐藏在暗处的“怪兽”,随时可能吞噬我们程序的性能和稳定性。无论是服务器应用程序、大型模拟系统还是其他长时间运行的关键任务软件,有效地处理内存膨胀问题…...
ELK之路第二步——可视化界面Kibana
Kibana 1.安装2.解压3.修改配置4.启动 这部分内容就比较简单了,水一片文章。 1.安装 需要梯子 官网下载链接:https://www.elastic.co/cn/downloads/past-releases/kibana-7-3-0 如果你去官网下载页面,点击下载是404报错,记得切换…...
Nature Medicine病理AI汇总|CONCH:病理图像分析的零样本学习模型·顶刊精析·24-10-30
小罗碎碎念 最近在整理24年发表在Nature Medicine上的病理AI文章,简单列了一个表。 接下来我将按照先后顺序,系统的把这13篇文献分析完。其中底色做了填充的,代表商业公司在本论文中占据了一作或通讯。 本期推文介绍的模型是CONCH࿰…...
通过不当变更导致 PostgreSQL 翻车的案例分析与防范
在数据库管理领域,PostgreSQL 凭借其强大的功能和稳定性,赢得了广泛的认可。然而,即便是如此稳健的系统,在不当的变更操作下,也可能遭遇性能下降、数据丢失甚至系统崩溃的风险。本文将通过一个具体案例,分析…...
Windows高级技巧:轻松实现多进程窗口的连接与管理
在Windows操作系统中,管理多个进程窗口可能是一项复杂的任务,特别是在自动化测试或多任务处理时。本文将介绍一种高效的方法,通过Python编程和AirtestIDE工具,实现多进程窗口的便捷连接与管理。同时,将提供具体的代码示…...
洪水淹没制图
原文链接:洪水淹没制图https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247624956&idx2&sn2557e56396eed7568d27baf694dc86fe&chksmfa8da91bcdfa200d307ea12ab9f52394ca6ef0bea3111bd8a873b34c950bcd9441c377f13674&token1392391660&…...
程序员做游戏还是做网站好/如何做网站推广广告
如果面试官问你,类加载过程是哪几步? 巴拉巴拉巴拉…(加载、验证、准备、解析、初始化) 见这小伙子面容惊奇,脸泛红光,不由自主地就问了一下双亲委派模型说一下吧;遇见没准备充分的,…...
旅游网站专业化建设的要点/产品网络营销策划
基于窗体的身份验证是一项 ASP.NET 身份验证服务,它使应用程序能够提供自己的登录用户界面并进行自己的凭据验证。ASP.NET 对用户进行身份验证,将未经身份验证的用户重定向到登录页,并执行所有必要的 Cookie 管理。这种身份验证是许多网站使用…...
南开天津网站建设/引流推广效果好的app
POE 在Quora上非常受欢迎的手机聊天机器人Poe App已经集成ChatGPT助手!除了最初集成的三个聊天机器人Sage、Claude和Dragonfly外,Poe现在还加入了第四位ChatGPT。由于使用了ChatGPT API,因此Poe拥有真正的ChatGPT。 现在更是第一批集成了GP…...
做营销最好的网站源码/百度安装到桌面
在安装好Maven之后,默认的~/.m2目录下是没有maven仓库配置文件settings.xml的,默认使用的是官方的仓库,访问速度会非常慢,我们需要配置下国内的仓库。 创建~/.m2/settings.xml文件,文件内容如下: <?xm…...
常熟高端网站建设/石家庄seo代理商
实现了五层协议1)物理层:对应osi的物理层2)网络接口层;osi的数据链路层3)internet层:osi模型在internet网使用前提出,未考虑网间连接。4)传输层:5)应用层:对应…...
广州互联网公司排名前20/seo问答
描述 欢迎来到猫咪系列题目之猫咪银行。 这也是猫咪占领世界的计划之一,通过开设猫咪银行出售 flag 来学习人类割韭菜的技巧。 通过理财一般来说都得不到,找漏洞 涉及购买、货币的一般先考虑溢出 找溢出点 可以修改的 value 有买入分钟和买入份额 挨…...