当前位置: 首页 > 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;欢迎各…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...