Java【多线程基础2】 Thread类 及其常用方法
文章目录
- 前言
- 一、Thread类
- 1, 构造方法
- 2, 常用成员属性
- 3, 常用成员方法
- 3.1, start 启动线程
- 3.2, interrupt 中断线程 (重点)
- 3.2.1, 手动设置标记位
- 3.2.2, 使用内置标记位
- 3.3.3, interrupt 方法 的作用
- 3.3 sleep 休眠线程
- 3.4, jion 等待线程
- 3.5 获取当前线程的引用
- 总结
前言
各位读者好, 我是小陈, 这是我的个人主页
小陈还在持续努力学习编程, 努力通过博客输出所学知识
如果本篇对你有帮助, 烦请点赞关注支持一波, 感激不尽
希望我的专栏能够帮助到你:
JavaSE基础: 从数据类型 到 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统等
Java数据结构: 顺序表, 链表, 二叉树, 堆, 哈希表等 (正在持续更新)
JavaEE初阶: 多线程, 网络编程, html, css, js, severlet, http协议, linux等(正在持续更新)
上篇介绍了[多线程基础篇1], 主要内容 : 线程 的概念, 线程 和 进程 的区别, 以及如何创建线程
本篇继续介绍多线程相关的基础内容, 内容较多, 分为若干篇持续分享
提示:是正在努力进步的小菜鸟一只,如有大佬发现文章欠佳之处欢迎批评指点~ 废话不多说,直接上干货!
一、Thread类
Thread类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread类 的对象与之关联
每一个线程, 都需要被描述(具体被描述什么, 下面再说), Thread类 的对象就是用来描述一个线程的
学习一个类, 要从它的构造方法学起
1, 构造方法
1, 无参构造方法 :
在上一篇介绍线程的创建方式时, 使用到了匿名内部类继承Thread, 重写 run 方法
的方式, 这就是无参构造法的使用
Thread thread = new Thread() {@Overridepublic void run() {System.out.println("一个新的thread线程");}};
2, 一个参数的构造方法 : 参数是 String 类型的 name , 表示线程的名字
其实就是方法1 的创建线程方式, 构造方法参数可以传递一个"name", 唯一的作用只是程序员知道自己创建的线程是谁, 方便多线程中代码调试
// 给这个线程命名为"喜羊羊"Thread thread = new Thread("喜羊羊") {@Overridepublic void run() {System.out.println("一个新的thread线程");}};thread.start();// 输出线程的名字System.out.println("thread线程的名字是: " + thread.getName());
3, 一个参数的构造方法 : 参数是 Runnable 对象
在上一篇介绍线程的创建方式时, 使用到了lambda表达式
的方式, 本质上就是匿名内部类实现了 Runnable 接口, 重写 run 方法
, 把 Runnable 对象作为参数
Thread thread = new Thread( () -> {while(true) {System.out.println("一个新的thread线程");}});
4, 两个参数的构造方法 : 一个是 Runnable 接口, 一个是 String 类型的 name
使用 lambda 表达式传参之后, 再传入一个字符串即可
Thread thread = new Thread(() -> {System.out.println("一个新的thread线程");}, "美羊羊"); // 给这个线程命名为"美羊羊"thread.start();// 输出线程的名字System.out.println("thread线程的名字: " + thread.getName());
2, 常用成员属性
1, ID . 获取 ID 使用 getId()
表示线程的唯一身份表示, 不会重复
2, 名称 . 获取名称使用 getName()
表示线程的名字, 对代码调试有帮助
3, 状态 . 获取状态使用 getState()
表示线程所处的情况, 下面会详细讨论
4, 优先级 . 获取优先级使用 getPriority()
优先级高线程的理论上会被优先调度, 但是线程是操作系统进行调度执行的基本单位
所以线程被调度的顺序归根结底还是操作系统决定的
5, 是否为后台线程(默认为前台) . 获取是否为后台线程使用 isDaemon()
前台线程会阻止进程的结束, 后台线程不会, 啥意思?
java 进程中的所有前台线程都结束 java 进程才能结束, 后台线程不管是否结束, java 进程该结束就结束
可以通过 setDaemon() 把线程改为后台线程(true)
6, 是否存活 . 获取是否存活使用 isAlive()
run 方法结束了, 说明线程执行完了, 就不存在了(不存活了), 或者 run 方法执行之前, 线程也不存在(不存活)
7, 是否被中断 . 获取是否被中断使用 isInterrupted()
这个下面介绍 interrupt 方法时会介绍到
代码展示:
Thread thread = new Thread(() -> {}, "美羊羊");System.out.println("-----调用 start 方法之前-----");System.out.println("thread线程 的状态 : " + thread.getState() + " (这是啥意思? 下面会介绍到)");System.out.println("thread线程 是否存活 : " + thread.isAlive() + " 此时 thread线程 不存在, 所以不存活");System.out.println(" ");thread.start();System.out.println("-----调用 start 方法时-----");System.out.println("thread线程 是否存活 : " + thread.isAlive() + " 此时 thread线程 正在执行, 所以不存活");System.out.println(" ");System.out.println("-----调用 start 方法之后-----");// 1, 获取thread线程的IDSystem.out.println("1, thread线程 的 id : " + thread.getId());// 2, 获取thread线程的名字System.out.println("2, thread线程 的名字 : " + thread.getName());// 3, 获取thread线程的状态System.out.println("3, thread线程 的状态 : " + thread.getState() + " (这是啥意思? 下面会介绍到)");// 4, 获取thread线程的优先级System.out.println("4, thread线程 的优先级 : " + thread.getPriority());// 5, thread线程是否为后台线程System.out.println("5, thread线程 是否为后台线程 : " + thread.isDaemon() + "默认都是false");// 6, thread线程是否存活System.out.println("6, thread线程 是否存活 : " + thread.isAlive() + " 此时 thread线程 已经执行完了, 所以不存活");// 7, thread线程是否被中断System.out.println("7, thread线程 是否被中断 : " + thread.isInterrupted());
3, 常用成员方法
3.1, start 启动线程
这个方法已经使用过很多次了, 再做一些强调 :
重写了 run 方法只是用代码描述了线程要执行什么操作
上篇介绍了很多方式用来创建线程对象, 创建了线程对象不代表线程开始执行
程序员自己调用 run 方法虽然也会执行方法体中的代码, 但并没有启动新的线程
调用 start 方法才会启动一个线程, 这个被创建出来的线程才会真正独立执行
3.2, interrupt 中断线程 (重点)
3.2.1, 手动设置标记位
如果在 run 方法中执行循环打印, 循环条件为 true
, 那么调用 start 方法启动线程后, 这个线程将无法结束
如果我们提前设置一个标记位 flag 为 false, 循环条件为 !flag
, 并且每执行一次打印, 就休眠 1000 毫秒, 此时线程仍无法结束
使用 sleep 方法需要使用 try-catch 语句捕获一个 InterruptedException异常, 表示休眠期间被打断就会抛出异常
catch 语句中的 e.printStackTrace(); 就是在出现异常时用来打印调用栈信息的
// 成员属性 flagprivate static boolean flag = false;public static void main(String[] args) {Thread thread = new Thread(() -> {while(!flag) {System.out.println("一个新的thread线程");try {// 打印一次, 休眠 1 秒 Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});
然后, 令主线程休眠 3000 毫秒后把 flag 设置为 true
,
thread.start();try {Thread.sleep(3000);flag = true;} catch (InterruptedException e) {e.printStackTrace();}
此时 thread 线程中的循环不满足循环条件
, 就会结束, 主线程 和 thread 线程的并发执行结果如下 :
3.2.2, 使用内置标记位
上面是我们手动设置了标记位
而 Thread类 的常见属性中提到的 isInterrupted(), 就是内置的标记位, 默认为 false , 类似于刚刚代码里的 flag, 我们用 isInterrupted() 替换上面的 flag :
// 省略其他代码while(!Thread.currentThread().isInterrupted()) {// 省略其他代码
Thread . currentThread() 是获取当前线程的示例, 也就是 thread
所以 : Thread . currentThread() . isInterrupted() 等同于 thread . isInterrupted()
只不过此时还没有完成对 thread 的初始化, 不能如后者那样写
接下来主线程中如何修改标记为呢? 就是使用 interrupt 方法 直接中断线程
// 省略其他代码try {Thread.sleep(3000);thread.interrupt();} catch (InterruptedException e) {e.printStackTrace();}
程序会如何执行呢? 需要先看看 interrupt 方法 到底有什么用
3.3.3, interrupt 方法 的作用
1, 会把标志位设为 true, 执行完 interrupt 之后 isInterrupted 的值就被设为 true 了
2, 如果线程处于阻塞状态, 就会取消阻塞状态, 上述代码中因为 sleep 方法, thread线程 会处于阻塞态(休眠), interrupt 就会让休眠结束, sleep 抛出异常,
所以, 按理说, 这个并发执行的程序最终会以一个异常结束
可以看到, catch 语句捕获了异常, 说明线程确实被打断了, 可是为什么线程没有结束, 还在循环打印呢 ? 原因是因为 sleep 方法
3.3 sleep 休眠线程
关于 sleep 方法的使用 以上代码已经用过很多次了, 这里再做个总结 :
参数为毫秒, 表示 sleep 方法执行后, 线程休眠多久
需要用 try-catch 捕获 InterruptedException 这个受查(编译时)异常
, 如果休眠时被中断, 就会抛出异常
但是, sleep方法 还有一个重要操作 ! !
在休眠时如果被唤醒, sleep方法会自动把标志位清空: 设置成 false
这就导致了在上述代码中, 为啥调用了 interrupt 方法后, 线程没有真正被中断, 就是因为标志位又被设置成了 false , 所以程序仍然会执行循环
sleep 方法为什么会这么做呢?
原因是, Thread类 并不希望线程执行了 interrupt 方法之后就立即被中断, 这样是很霸道很强硬的做法
它希望的效果是, interrupt 方法, 仅仅起到一个 “提示” 或者 “通知” 的作用, 然后由程序员编写代码, 用代码逻辑来控制线程
是立即结束, 还是等一会再结束, 还是无视这个 “通知”
比如我女朋友让我别刷抖音了, 陪她出门逛街, 我完全可以立即关掉抖音
但如果我此时在努力敲代码, 有很重要的学习任务, 我可以和她商量, 能不能等我学习完再去
如果我无论什么状态下都立即中断手头的事儿, 显然是不合理的
站在我的角度来说, 只有我自己最了解, 最关心自己, 知道现在应该做什么
站在程序员的角度上, 只有程序员最了解, 最关心自己写的代码, 知道当前的代码是否应该结束, 所以交给程序员决定何时中断才是最优解
那么在上述代码中, 如何实现立即中断呢? 只需要在捕获异常之后加一个 break 即可
// 省略其他代码} catch (InterruptedException e) {e.printStackTrace();break;}// 省略其他代码
3.4, jion 等待线程
有的时候, 多个线程不能满足并发的条件, 可能需要等某个线程执行完再并发执行
例如我要和女朋友去约会, 我应该去她家楼下接她, 如果我到她家楼下后, 她还在化妆, 我应该等她下楼之后再一起去约会
我们先再复习一下多线程的并发执行效果 :
Thread thread = new Thread( () -> {// 循环打印 5 次for (int i = 0; i < 5; i++) {System.out.println("thread线程");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});thread.start();// 循环打印 5 次for (int i = 0; i < 5; i++) {System.out.println("主线程");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
两条打印语句交替执行, 如果我在调用 start 方法启动 thread线程 之后, 再写一个 thread.join()
, 会发生什么呢?
// 省略其他代码thread.start();thread.join();// 省略其他代码
可以看到, 当 thread线程 执行完了所有的循环打印之后, 主线程 才开始循环打印, 说明此时, 主线程 是等待 thread线程 结束之后才执行的
所以 : 主线程调用 thread.join 就是 主线程 等待 thread线程
3.5 获取当前线程的引用
上面已经使用过了, 这是一个静态方法, 会获取当前线程的引用, 然后可以继续进行其他操作
例如, 在 run 方法中执行完打印语句之后, 再打印一下当前线程的名字
Thread thread = new Thread( () -> {for (int i = 0; i < 5; i++) {System.out.print("thread线程");System.out.println(" 我的名字叫 : " + Thread.currentThread().getName());}},"懒羊羊");thread.start();
总结
以上就是本篇的全部内容, 主要介绍了
Thread类中的 : 构造方法, 成员属性, 成员方法
其中, interrupt方法 和 sleep方法 有个特殊点, 需要重点理解
如果本篇对你有帮助,请点赞收藏支持一下,小手一抖就是对作者莫大的鼓励啦😋😋😋~
上山总比下山辛苦
下篇文章见
相关文章:
Java【多线程基础2】 Thread类 及其常用方法
文章目录前言一、Thread类1, 构造方法2, 常用成员属性3, 常用成员方法3.1, start 启动线程3.2, interrupt 中断线程 (重点)3.2.1, 手动设置标记位3.2.2, 使用内置标记位3.3.3, interrupt 方法 的作用3.3 sleep 休眠线程3.4, jion 等待线程3.5 获取当前线程的引用总结前言 各位读…...
JVM调优实战及常量池详解
目录 阿里巴巴Arthas详解 Arthas使用场景 Arthas使用 GC日志详解 如何分析GC日志 CMS G1...
ChatGPT研究分析:GPT-4做了什么
前脚刚研究了一轮GPT3.5,OpenAI很快就升级了GPT-4,整体表现有进一步提升。追赶一下潮流,研究研究GPT-4干了啥。本文内容全部源于对OpenAI公开的技术报告的解读,通篇以PR效果为主,实际内容不多。主要强调的工作…...
我为什么要写博客,写博客的意义是什么??
曾经何时我也不知道,怎样才能变成我自己所羡慕的大佬!!在一次次的CSDN阅读的过程中,结实了许多志同道合的人!!包过凉哥,擦姐……大佬,但是,很遗憾,与这些人只…...
ssm框架之spring:浅聊AOP
AOP(Aspect Oriented Programming),是一种设计思想。先看一下百度百科的解释: 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态…...
k8s详解
一、k8s中的yaml文件 JSON格式:主要用于api接口之间信息的传递YAML格式:主要用于配置和管理,YAML是一种简洁的非标记性语言,内容格式人性化 YAML格式: 大小写敏感使用缩进代表层级关系,不支持TAB制表符缩…...
计算机操作系统(第四版)第一章操作系统引论 1.1操作系统的目标和作用
第一章操作系统引论 1.1操作系统的目标和作用 什么是操作系统OS? 配置在计算机硬件上的第一层软件是对硬件的首次扩充。 是最重要的系统软件,其他系统软件应用软件都依赖于操作系统的支持。 操作系统主要作用? 管理计算机系统所有硬件设…...
git push解决办法: ! [remote rejected] master -> master (pre-receive hook declined)
项目经理远程创建了一个空项目,无任何内容,给我赋予的developer账号权限,本地改为后提交代码试了很多次都上传不上去,报错如下: ! [remote rejected] master -> master (pre-receive hook declined)先说结果&#x…...
jQuery 遍历方法总结
遍历方法有:1、add(),用于把元素添加到匹配元素的集合中;2、children(),用于返回被选元素的所有直接子元素;3、closest(),用于返回被选元素的第一个祖先元素;4、contents(),用于返回…...
OKHttp 源码解析(二)拦截器
游戏SDK架构设计之代码实现——网络框架 OKHttp 源码解析(一) OKHttp 源码解析(二)拦截器 前言 上一篇解读了OKHttp 的基本框架源码,其中 OKHttp 发送请求的核心是调用 getResponseWithInterceptorChain 构建拦截器链…...
如何修改设置浏览器内核模式
优先级: 强制锁定极速模式 >手动切换(用户)>meta指定(开发者)>浏览器兼容列表(浏览器) 需要用360安全浏览器14,chromium108内核,下载地址https://bbs.360.cn/t…...
30个Python常用小技巧
1、原地交换两个数字 1 2 3 4 x, y 10, 20 print(x, y) y, x x, y print(x, y) 10 20 20 10 2、链状比较操作符 1 2 3 n 10 print(1 < n < 20) print(1 > n < 9) True False 3、使用三元操作符来实现条件赋值 [表达式为真的返回值] if [表达式] else [表达式…...
ubuntu解决中文乱码
1、查看当前系统使用的字符编码 ~$ locale LANGen_US LANGUAGEen_US: LC_CTYPE"en_US" LC_NUMERIC"en_US" LC_TIME"en_US" LC_COLLATE"en_US" LC_MONETARY"en_US" LC_MESSAGES"en_US" LC_PAPER"en_US" …...
2022年全国职业院校技能大赛(中职组)网络安全竞赛试题——MYSQL安全测试解析(详细)
B-3任务三:MYSQL安全测试 *任务说明:仅能获取Server3的IP地址 1.利用渗透机场景kali中的工具确定MySQL的端口,将MySQL端口作为Flag值提交; 2.管理者曾在web界面登陆数据库,并执行了select <?php echo \<pre>\;system($_GET[\cmd\]); echo \</pre>\; ?…...
C++ map和unordered_map的区别
unordered_map 类模板和 map 类模板都是描述了这么一个对象:它是由 std::pair<const Key, value> 组成的可变长容器; 这个容器中每个元素存储两个对象,也就是 key - value 对。 1. unordered_map 在头文件上,引入 <unor…...
BCSP-玄子JAVA开发之JAVA数据库编程CH-04_SQL高级(二)
BCSP-玄子JAVA开发之JAVA数据库编程CH-04_SQL高级(二) 4.1 IN 4.1.1 IN 子查询 如果子查询的结果为多个值,就会导致代码报错解决方案就是使用 IN 关键字,将 替换成 IN SELECT …… FROM 表名 WHERE 字段名 IN (子查询);4.1.…...
学习java——②面向对象的三大特征
目录 面向对象的三大基本特征 封装 封装demo 继承 继承demo 多态 面向对象的三大基本特征 我们说面向对象的开发范式,其实是对现实世界的理解和抽象的方法,那么,具体如何将现实世界抽象成代码呢?这就需要运用到面向对象的三大…...
初阶数据结构 - 【单链表】
目录 前言: 1.概念 链表定义 结点结构体定义 结点的创建 2.链表的头插法 动画演示 代码实现 3.链表的尾插 动画演示 代码实现 4.链表的头删 动画演示 代码实现 5.链表的尾删 动画演示 代码实现 6.链表从中间插入结点 动画演示 代码实现 7.从单…...
第五周作业、第一次作业(1.5个小时)、练习一
一、创建servlet的过程没有太多好说的,唯一需要注意的就是:旧版本的servlet确实需要手动配置web.xml文件,但是servlet2.5以后,servlet的配置直接在Java代码中进行注解配置。我用的版本就不再需要手动去配置web.xml文件了,所以我只…...
【正点原子FPGA连载】 第三十三章基于lwip的tftp server实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南
第三十三章基于lwip的tftp server实验 文件传输是网络环境中的一项基本应用,其作用是将一台电子设备中的文件传输到另一台可能相距很远的电子设备中。TFTP作为TCP/IP协议族中的一个用来在客户机与服务器之间进行文件传输的协议,常用于无盘工作站、路由器…...
蓝桥冲刺31天之316
如果生活突然向你发难 躲不过那就迎面而战 所谓无坚不摧 是能享受最好的,也能承受最坏的 大不了逢山开路,遇水搭桥 若你决定灿烂,山无遮,海无拦 A:特殊日期 问题描述 对于一个日期,我们可以计算出年份的各个…...
说一个通俗易懂的PLC工程师岗位要求
你到了一家新的单位,人家接了一套新的设备,在了解设备工艺流程之后,你就能决定用什么电气元件,至少95%以上电气原件不论你用过没用过都有把握拍板使用,剩下5%,3%你可以先买来做实验,这次不能用&…...
今年还能学java么?
“Java很卷”、“大家不要再卷Java了”,经常听到同学这样抱怨。但同时,Java的高薪也在吸引越来越多的同学。不少同学开始疑惑:既然Java这么卷,还值得我入行吗? 首先先给你吃一颗定心丸:现在选择Java依然有…...
ajax学习1
不刷新页面的情况下,向服务端发送请求,异步的js和XMLajax不是新的编程语言,只是把现有标准组合到一起使用的新方式...
一题多解-八数码(万字长文)
16 张炜皓 (ζ͡顾念̶) LV 5 1 周前 在做这道题前,先来认识一下deque双端队列 C STL 中的双端队列 题目连接 使用前需要先引入 头文件。 #include; STL 中对 deque 的定义 // clang-format off template< class T, class Allocator std::allocator class d…...
九种跨域方式实现原理(完整版)
前言 前后端数据交互经常会碰到请求跨域,什么是跨域,以及有哪几种跨域方式,这是本文要探讨的内容。 一、什么是跨域? 1.什么是同源策略及其限制内容? 同源策略是一种约定,它是浏览器最核心也最基本的安…...
fighting
目录Mysqlgroup by和 distinct哪个性能好java觉得Optional类怎么样isEmpty和isBlank的用法区别使用大对象时需要注意什么内存溢出和内存泄漏的区别及详解SpringResource和Autowired的起源既生“Resource”,何生“Autowired”使用Autowired时为什么Idea会曝出黄色警告…...
网络安全日志监控管理
内部安全的重要性 无论大小,每个拥有IT基础设施的组织都容易发生内部安全攻击。您的损失等同于黑客的收益:访问机密数据、滥用检索到的信息、系统崩溃,以及其他等等。专注于网络外部的入侵是明智的,但同时,内部安全也…...
线程池的使用:如何写出高效的多线程程序?
目录1.线程池的使用2.编写高效的多线程程序Java提供了Executor框架来支持线程池的实现,通过Executor框架,可以快速地创建和管理线程池,从而更加方便地编写多线程程序。 1.线程池的使用 在使用线程池时,需要注意以下几点ÿ…...
React 架构流程概览
React 架构流程概览 文章目录React 架构流程概览启动React项目流程分析各部分解析调度器协调器渲染器总结启动React项目 启动项目,并打开 Performance 面板 流程分析 首先找到入口函数 整个 render 下面的调用栈就是首屏渲染要执行的流程。 render 过程大致分为…...
网站建设应该注意哪些原则/短视频矩阵seo系统源码
第一步启用Ad Hoc Distributed Queries 在SQLserver执行以下的语句: exec sp_configure show advanced options,1 reconfigure exec sp_configure Ad Hoc Distributed Queries,1 reconfigure ----允许在进程中使用ACE.OLEDB.12 在安装了 ACE2010的驱动才可以执行…...
移动互联网开发找工作/武汉seo结算
综观多家企业的ERP实施情况,笔者发现有一个比较大的误区,即都忽视了计划在工作中的作用。有些企业虽然意识到计划的重要性,但是在实际工作中会因为种种原因无法落实到实处。笔者认为,计划是ERP项目中的灵魂,企业用户应…...
怎么做网站筛选功能/糕点烘焙专业培训学校
这是悦乐书的第318次更新,第339篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第186题(顺位题号是804)。国际莫尔斯电码定义了一种标准编码,其中每个字母映射到一系列点和短划线,如下所示:“…...
重庆网站建设公司销售/seo外包网络公司
返回上级目录:iOS面试专题一 文章目录0.下面的说法只是针对oc,swift中没有__block0.1 swift闭包的底层原理1.什么情况下需要使用__block2.笔试题的坑:对被截获变量赋值才需要__block3.那些变量需要__block,那些不需要4.笔试题0.下面的说法只是针对oc,swift中没有__b…...
ps网页版在线制作/家庭优化大师
引用:http://www.williamlong.info/archives/3181.html CC攻击(Challenge Collapsar)是DDOS(分布式拒绝服务)的一种,也是一种常见的网站攻击方法,攻击者通过代理服务器或者肉鸡向向受害主机不停…...
牛商网做的网站怎么样/怎么网络推广
这个是Ralph kimball ETL的书籍,其中第10章主要讲如何管理数据仓库团队,ETL团队是属于数据仓库团队的;第一章和第二章是概况性的介绍,强烈建议大家都看下1/2/10章,对于大家形成对数据仓库和ETL共同的认识。 下面和大家…...