多线程之旅:属性及其基本操作
上次分享到了,多线程中是是如何创建的,那么接下来,小编继续分享下多线程的相关知识。
多线程中的一些基本属性。
基本属性
属性 | 获取方法 |
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否后台线程 | isDemo() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
那么其中这些属性名称有着什么意思呢?
ID:是线程唯一的标识,不同线程不会重复
这里是jvm自动分配的,不能手动设置
名称:是各种调试工具用到的东西,可以帮助调试和日志记录
Thread对象的身份标识
状态:表示线程当前所处的一个情况
一般初学听的更多是就绪/阻塞
后面详细介绍。
优先级:影响线程调度一个工具,理论上来说,优先级高的更容易被调度到
设置不同的优先级,会影响系统的调度,这里的影响有着多种因素:
操作系统调度算法、优先级映射……
后台线程:特殊类型的线程,主要是为程序提高服务和支持功能。
有着后台线程,那么也有着前台线程
那么又是前台线程呢?
前台线程也是一个特殊线程,默认创建的。
有个值得注意的,前台线程会影响jvm的退出,前台线程结束后,jvm才会退出。
后台线程是不会影响jvm的退出的。
存活:可以简单理解为,执行run方法是否结束了
线程中断:用于请求线程停止当前工作的一种机制。
ok,接下来以一个代码来演示下
public static void main(String[] args) {Thread t=new Thread(()->{while (true){System.out.println("hello world");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();//获取线程属性//获取IDSystem.out.println("ID:"+t.getId());//线程名字System.out.println("name:"+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());}
在代码运行期间,截了以下的运行图:
从运行结果来看,ID被jvm自动分配为:22
name被jvm自动填充为Thread-0
这里值得注意的是,main方法也是一个线程,还是个主线程,而且有着自己独属的名字
就直接命名为main
而后创建的线程从Thread-n开始(这是默认填充名字),n从0开始
状态则显示为TIMED_WAITING
这里简单介绍下这里的几种状态:
状态 | 含义 | 例子 |
NEW | 线程被创建但尚未启动 | 新买的车还没发动。 |
RUNNABLE | 线程正在执行或准备执行 | 车辆在路上行驶。 |
BLOCKED | 线程等待获取锁 | 等待电梯开门。 |
WAITING | 线程无限期等待另一个线程执行特定操作 | 在咖啡店等朋友,不确定他们什么时候到。 |
TIMED_WAITING | 线程等待一段时间后继续执行 | 在咖啡店等朋友,但只愿意等 10 分钟 |
TERMINATED | 线程已完成执行,不能再次启动 | 完成购物并离开商店。 |
从图中可以看到优先级为5
那么此时这个5是什么意思呢?
在Java的优先级中,优先级是一个整数值,范围到MIN_PRIORITY(1)->MAX_PRIORITY(10);
Thread.MIN_PRIORITY
: 最低优先级,值为 1。Thread.NORM_PRIORITY
: 默认优先级,值为 5。Thread.MAX_PRIORITY
: 最高优先级,值为 10。
接着看到是否存活,很显然,线程run方法执行的内容是死循环,所以是存在这个线程,即存活
值得注意的是,我们是通过创建线程对象,任何才有通过对象,去创建线程。
那么此时,可能会出现Thread对象存在,但是线程是不存在的了(注意:是不会出现,线程存在,Thread对象不存在的)
比如:1.调用start之前,内核中,还没创建线程呢
2.线程中的run方法执行完毕了,内核中的线程自然就无了,但此时Thread对象,仍然存在
是否被中断,这里的中断内容,后续会讲到。
那么接下来讲讲这个线程的一些核心操作
一些核心操作
1.线程创建
这个前一篇文章已经讲述过了噢,那么接下来仅仅补充下
这个线程创建,即是调用这个start方法,那么值得注意的是,start方法不能启动多次,只能一次,
因为一个Thread对象,对应一个线程,在jvm中。
多次启动后的报错信息
还有就是,在线程中是可以启动其他线程的,也可以创建其他线程的
不只是在main方法中去创建线程。
2.线程的中断
即是一个线程结束
在java中,这个线程中断结束,是比较温柔的做法 ,假设B正在运行,那么此时,A想让B结束,
那么A就是想办法,把B的run() 方法运行完即可。
这里有一个简单直接的做法可以演示
public class Demo11 {private static boolean isQuit=false;public static void main(String[] args) throws InterruptedException {//不能写在内部,因为我们下面创建线程任务是使用lambda表达式,写在内部涉及到变量捕获
// boolean isQuit=false;Thread t=new Thread(()->{while (!isQuit){System.out.println("hello world");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();Thread.sleep(2000);//在这里影响t线程结束isQuit=true;System.out.println("t线程结束!");}
}
当然,还有一个方法,就是通过Thread.currentThread()获取到当前线程的实例,去判断下是否被中断了
public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{//获取当前线程的引用Thread currentThread=Thread.currentThread();//默认为falsewhile (!currentThread.isInterrupted()){System.out.println("hello world");try {Thread.sleep(1000);} catch (InterruptedException e) {System.out.println("catch语句已执行!");break;
// throw new RuntimeException(e);}}});t.start();Thread.sleep(4000);//这里来控制t线程结束,调用后,currentThread.isInterrupted()返回truet.interrupt();}
此时为什么会执行到catch语句的内容呢?
这是因为在主线程中呢,t.interrupt();会让这个中断标志设置为true,一开始为false。
那么此时t线程中的,sleep()正在休眠,此时会导致sleep()抛出InterruptedException,此时呢,就会执行到catch语句代码
值得注意的是,sleep()唤醒后,又会重新设置这个中断标志位,即恢复默认情况
那么此时如若我们呢catch语句没有中断操作,除了它,它还是会继续打印hello world代码。
所以Interrupt方法能够设置标志位,也能唤醒sleep等阻塞方法
而且sleep方法唤醒后,又能清空标志位。
3.线程等待
我们之前讲到,这个操作系统针对多个线程的执行,是一个随机调度,抢占式执行的过程。
那么这个线程等待呢,就是确定两个线程的“结束顺序”
比如A线程中调用B.join(),那么这个意思就是让A线程等待B线程 先结束,然后再执行A线程的内容
这个join就是线程等待的关键字。
我们可以使用一个代码来演示下
public static void main(String[] args) throws InterruptedException {Thread t1=new Thread(()->{for(int i=0;i<4;i++){System.out.println("hello t1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t2=new Thread(()->{for(int i=0;i<=4;i++){System.out.println("hello t2");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.start();t2.start();t1.join();t2.join();
所以运行结果中,可能会带着交替出现的效果。
由于是线程是随机调度的,所以打印结果,有可能使交替出现,也有可能不是。
这里我们使main主线程等待t1、t2线程
那么其实也可以t1等待t2线程,或者也可以t2等待t1,甚至多个线程进行等待
那么刚刚使用的这个是无参版本的,
那么此时这个join有可能就是会出现死等的情况,有时候往往不是一个好选择
所以java这里呢,提供了两个带参数的版本
public void join(long millis) | 等待线程结束,最多等待millis毫秒 |
public void join(long millis,int nanos) | 同理,但是提供的精度会更高 |
所以我们如若使用到这个带参数的版本,这样等预定的时间过后,就会执行其他任务了,而不是死等了。
完~
相关文章:

多线程之旅:属性及其基本操作
上次分享到了,多线程中是是如何创建的,那么接下来,小编继续分享下多线程的相关知识。 多线程中的一些基本属性。 基本属性 属性获取方法IDgetId()名称getName()状态getState()优先级getPriority()是否后台线程isDemo()是否存活isAlive()是…...

数据表中的数据插入、更新和删除
文章目录 一、表的插入二、更新表中的数据记录三、删除表中的数据记录 一、表的插入 插入数据记录是常见的数据操作,可以显示向表中增加的新的数据记录。在MySQL中可以通过“INSERT INTO”语句来实现插入数据记录,该SQL语句可以通过如下4种方式使用&…...

Q_OBJECT宏报错的问题
在Qt中继承QObject,并且加上Q_OBJECT宏,有时候会报错,比如我的错误: error: debug/httpmgr.o:httpmgr.cpp:(.rdata$.refptr._ZTV7HttpMgr[.refptr._ZTV7HttpMgr]0x0): undefined reference to vtable for HttpMgr 意思是没有虚…...

提升性能300ms:深入解析Spring多表联接查询优化与SQL调优实战
优化所需知识点(必须掌握) 索引篇 explain命令 重点:这是后续分析是否使用索引以及使用是否恰当的工具 作用:查看sql的执行计划,可以看sql语句是否使用了索引,索引的使用情况,以及sql的性能。 …...

增量导入和全量导入的区别是什么?
定义 全量导入:是指将数据源中的所有数据一次性全部导入到目标系统中。例如,一个电商公司要将其旧数据库中的所有商品信息(包括商品名称、价格、库存等)全部迁移到新的数据库系统中,这个过程就是全量导入。这种方式会覆…...

【百度智能云客悦智能客服】搭建AI agent智能对话 - 购车推荐
前期准备 平台链接:https://keyue.cloud.baidu.com/ 一、开始创建 二、会话流程配置 我们以购车推荐的案例,来进行 AI agent 配置演示 1.添加开场白 在 起始主题 画布中,我们可以配置 AI agent 的开场白,画布左侧默认有 开始 …...

【HTML+CSS+JS+VUE】web前端教程-3-标题标签
标题介绍与应用 标题是通过<h1>-<h6>标签进行定义的 <h1>定义最大的标题 <h6>定义最小的标题<h1...

逐笔成交逐笔委托Level2高频数据下载和分析:20250102
level2逐笔成交逐笔委托下载 链接: https://pan.baidu.com/s/1p7OOj5p-QGFrWkt6KKoYng?pwd7f4g 提取码: 7f4g Level2逐笔成交逐笔委托数据分享下载 通过Level2逐笔成交和逐笔委托这种每一笔的毫秒级别的数据可以分析出很多有用的点,包括主力意图,虚假动…...

JavaEE之线程池
前面我们了解了多个任务可以通过创建多个线程去处理,达到节约时间的效果,但是每一次的线程创建和销毁也是会消耗计算机资源的,那么我们是否可以将线程进阶一下,让消耗计算机的资源尽可能缩小呢?线程池可以达到此效果&a…...

java 中 main 方法使用 KafkaConsumer 拉取 kafka 消息如何禁止输出 debug 日志
pom 依赖: <dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId><version>2.5.14.RELEASE</version> </dependency> 或者 <dependency><groupId>org.ap…...

【后端面试总结】Golang可能的内存泄漏场景及应对策略
Golang可能的内存泄漏场景及应对策略 一、引言 Golang作为一种高性能、并发友好的编程语言,其内置的垃圾回收机制极大地简化了内存管理。然而,这并不意味着开发者可以完全忽视内存泄漏问题。在实际开发中,由于不当的资源管理、循环引用、以…...

Java 反射机制详解
在 Java 编程世界中,反射机制犹如一把神奇的钥匙,它能够打开许多隐藏在代码深处的 “大门”,让开发者突破常规的限制,实现一些极具灵活性的功能。今天,就跟随我一同深入探究 Java 反射机制的奥秘。 一、什么是反射 反…...

【k8s】scc权限 restricted、anyuid、privileged
文章目录 概述1. 内置的scc2. OpenShift如何确定pod的scc2.1 Pod未带SCC标签的情况2.2. Pod带有SCC标签的情况 参考 概述 在OpenShift(后文简称OCP)中,很早就一个概念:Security Context Constraints ,简称SCC…...

2025华数杯国际赛A题完整论文讲解(含每一问python代码+数据+可视化图)
大家好呀,从发布赛题一直到现在,总算完成了2025“华数杯”国际大学生数学建模竞赛A题Can He Swim Faster的完整的成品论文。 本论文可以保证原创,保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文…...

ThreadLocal 的使用场景
在现代电商平台中,ThreadLocal 常用于以下场景,特别是与线程隔离相关的业务中,以提高性能和简化上下文传递。 1. 用户上下文信息管理 场景:在用户发起的每次请求中,需要携带用户 ID、角色、权限等信息,而这…...

后端开发 Springboot整合Redis Spring Data Redis 模板
目录 redis 配置 RedisConfig 类 完整代码 代码讲解 1. 类定义和注解 2. 定义 RedisTemplate Bean 3. 配置 JSON 序列化 4. 配置 Redis 的 key 和 value 序列化方式 5. 完成配置并返回 RedisTemplate 总结 redis 服务接口实现类 类级别 注入 RedisTemplate 常用 Re…...

代码随想录算法训练营第 4 天(链表 2)| 24. 两两交换链表中的节点19.删除链表的倒数第N个节点 -
一、24. 两两交换链表中的节点 题目:24. 两两交换链表中的节点 - 力扣(LeetCode) 视频:帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点_哔哩哔哩_bilibili 讲解:代码随想录 dummy-…...

【RDMA学习笔记】1:RDMA(Remote Direct Memory Access)介绍
从帝国理工的PPT学习。 什么是RDMA Remote Direct Memory Access,也就是Remote的DMA,是一种硬件机制,能直接访问远端结点的内存,而不需要处理器介入。 其中: Remote:跨node进行数据传输Directÿ…...

网络安全常见的35个安全框架及模型
大家读完觉得有帮助记得关注和点赞!!! 01、概述 网络安全专业机构制定的一套标准、准则和程序,旨在帮助组织了解和管理面临的网络安全风险。优秀的安全框架及模型应该为用户提供一种可靠方法,帮助其实现网络安全建设…...

Elasticsearch介绍及使用
Elasticsearch 是一款基于 Lucene 库构建的开源、分布式、RESTful 风格的搜索引擎和分析引擎,具有强大的全文搜索、数据分析、机器学习等功能,广泛应用于日志分析、实时数据分析、全文检索等场景。 核心概念 索引(Index)…...

Leetocde516. 最长回文子序列 动态规划
原题链接:Leetocde516. 最长回文子序列 class Solution { public:int longestPalindromeSubseq(string s) {int n s.size();vector<vector<int>> dp(n, vector<int>(n, 1));for (int i 0; i < n; i) {dp[i][i] 1;if (i 1 < n &&…...

iOS 逆向学习 - Inter-Process Communication:进程间通信
iOS 逆向学习 - Inter-Process Communication:进程间通信 一、进程间通信概要二、iOS 进程间通信机制详解1. URL Schemes2. Pasteboard3. App Groups 和 Shared Containers4. XPC Services 三、不同进程间通信机制的差异四、总结 一、进程间通信概要 进程间通信&am…...

高级生化大纲
一,蛋白质化学: 蛋白质分离是生物化学和分子生物学研究中的一项基本技术,用于根据蛋白质的物理和化学特性将其从混合物中分离出来。 1. 离心分离法 离心分离法利用离心力来分离不同质量或密度的颗粒和分子。 差速离心:通过逐…...

YARN WebUI 服务
一、WebUI 使用 与HDFS一样,YARN也提供了一个WebUI服务,可以使用YARN Web用户界面监视群集、队列、应用程序、服务、流活动和节点信息。还可以查看集群详细配置的信息,检查各种应用程序和服务的日志。 1.1 首页 浏览器输入http://node2.itc…...

【Unity3D】利用IJob、Burst优化处理切割物体
参考文章: 【Unity】切割网格 【Unity3D】ECS入门学习(一)导入及基础学习_unity ecs教程-CSDN博客 【Unity3D】ECS入门学习(十二)IJob、IJobFor、IJobParallelFor_unity ijobparallelfor-CSDN博客 工程资源地址&…...

【大前端】Vue3 工程化项目使用详解
目录 一、前言 二、前置准备 2.1 环境准备 2.1.1 create-vue功能 2.1.2 nodejs环境 2.1.3 配置nodejs的环境变量 2.1.4 更换安装包的源 三、工程化项目创建与启动过程 3.1 创建工程化项目 3.2 项目初始化 3.3 项目启动 3.4 核心文件说明 四、VUE两种不同的API风格 …...

基于文件系统分布式锁原理
分布式锁:在一个公共的存储服务上打上一个标记,如Redis的setnx命令,是先到先得方式获得锁,ZooKeeper有点像下面的demo,比较大小的方式判决谁获得锁。 package com.ldj.mybatisflex.demo;import java.util.*; import java.util.co…...

简历整理YH
一,订单中心 1,调拨单 融通(Rocketmq)-订单中心:ECC_BMS123(已出单),125(分配),127(发货),129(收货) 通过RocketMq接入多场景订单数据 2,销售单 sap(FTP)-订单中心,下发1002,1003,…...

Kotlin 协程基础三 —— 结构化并发(二)
Kotlin 协程基础系列: Kotlin 协程基础一 —— 总体知识概述 Kotlin 协程基础二 —— 结构化并发(一) Kotlin 协程基础三 —— 结构化并发(二) Kotlin 协程基础四 —— CoroutineScope 与 CoroutineContext Kotlin 协程…...

微信小程序实现长按录音,点击播放等功能,CSS实现语音录制动画效果
有一个需求需要在微信小程序上实现一个长按时进行语音录制,录制时间最大为60秒,录制完成后,可点击播放,播放时再次点击停止播放,可以反复录制,新录制的语音把之前的语音覆盖掉,也可以主动长按删…...