Java中线程的常用方法(并发编程基础)

Java中线程的常用方法

sleep

  1. 调用sleep会让当前线程从Running进入TIMED WAITING状态
  2. 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时sleep方法会抛出InterruptedException
  3. 睡眠结束后的线程未必会立刻得到执行
  4. 建议用TimeUnitsleep代替Threadsleep来获得更好的可读性

实例代码

public class SleepMethodDemo {public static void main(String[] args) {Logger log = Logger.getLogger("SleepMethodDemo");Thread t1 = new Thread(() -> {try {//                Thread.sleep(1000);//建议使用log.info("Thread t1 sleep 1000ms");TimeUnit.MICROSECONDS.sleep(1000);} catch (InterruptedException e) {log.info("Thread t1 interrupted");e.printStackTrace();}}, "t1");t1.start();log.log(Level.INFO, "main thread end");t1.interrupt();}}

控制台输出
在这里插入图片描述

这里的TimeUtit本质上还是去调用了Thread.sleep(),只是可读性增强,我们可以查看一下源码

在这里插入图片描述

yield

  1. 调用yield会让当前线程从Running进入Runnable就绪状态,然后调度执行其它线程
  2. 具体的实现依赖于操作系统的任务调度器(当cpu很空闲时,也就是没有太多资源抢占到cpu,哪怕执行此方法,操作系统也会将时间片给当前线程)

sleep 和 yield的区别

  1. sleep会有一段真正的等待时间,而yield基本上是马上执行
  2. sleep是将线程变为TIMED_WAITING状态,此时是不会被操作系统调度的,而yield是将线程变为就绪状态,是可以继续被系统调度的,也就是还是能够抢占cpu.

线程优先级

  • 线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
  • 如果cpu比较忙,那么优先级高的线程会获得更多的时间片,但cpu闲时,优先级几乎没作用.
    public class YieldAndPriority {public static void main(String[] args) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {int i = 0;while (true) {System.out.println(Thread.currentThread().getName() + " " + i++);}}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {int i = 0;while (true) {Thread.yield();//让出cpuSystem.out.println("       "+Thread.currentThread().getName() + " " + i++);}}});//设置优先级,优先级范围为1-10t1.setPriority(Thread.MAX_PRIORITY);t2.setPriority(Thread.MIN_PRIORITY);t1.start();t2.start();}}

sleep的应用

在没有利用cpu来计算时,不要让while(true)空转浪费cpu,这时可以使用yield或sleep来让出cpu的使用权给其他程序

    while(true){try{Thread.sleep(50);}catch(InterruptedException e){e.printStackTrace();}}
  • 可以用wait或条件变量达到类似的效果
  • 不同的是,后两种都需要加锁,并且需要相应的唤醒操作,一般适用于要进行同步的场景
  • sleep适用于无需锁同步的场景.

join

join方法实际上就是在一个线程当中等待另一个线程结束以后才开始执行自己的代码

该方法有两种,一种带参一种无参.

  • join() 等待线程运行结束
  • join() 等待线程运行结束,最多等待n毫秒

若线程执行完毕小于设定的最多等待时间,不会继续等待,以两者比较的最小值为准.

interrupt

打断 sleep,wait,join 的线程,会清空打断状态,打断过后,打断状态设为false.正常线程打断设置为true(但正常线程打断并不会立即停止运行,只是注上一个打断标记)

  • 示例: 打断sleep,wait,join线程.
    public class InterruptMethodDemo {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {System.out.println("t1 is interrupted");e.printStackTrace();}}, "t1");System.out.println("start t1");t1.start();t1.interrupt();TimeUnit.MICROSECONDS.sleep(50);System.out.println("t1.isInterrupted() = " + t1.isInterrupted());}}

结果展示
在这里插入图片描述

  • 示例:打断正常的线程
    public class InterruptNormalDemo {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (true) {}}, "t1");System.out.println("t1.start");t1.start();t1.interrupt();System.out.println("t1.interrupt()");TimeUnit.SECONDS.sleep(1);System.out.println("t1.isInterrupted() = " + t1.isInterrupted());}}

此时,线程t1并没有结束,而是继续在运行.

在这里插入图片描述

我们将代码改写,手动控制线程的执行与停止

    public class InterruptNormalDemo {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (true) {System.out.println("while t1.isInterrupted() = " + Thread.currentThread().isInterrupted());if(Thread.currentThread().isInterrupted()){break;}}}, "t1");System.out.println("t1.start");t1.start();Thread.sleep(1);t1.interrupt();System.out.println("t1.interrupt()");TimeUnit.SECONDS.sleep(1);System.out.println("t1.isInterrupted() = " + t1.isInterrupted());}}

结果为
在这里插入图片描述

实践运用interrupt(两阶段终止)

场景分析: 当前有一个业务,用来日志监控,每隔两秒进行监控,中途若被打断,停止监控.

我们可以运用两阶段终止的设计模式来进行.哪么是哪两个阶段呢

  • 第一个阶段,正常打断,也就是我们没有在线程睡眠时打断,此时打断标记为true
  • 第二个阶段,睡眠打断,也就是我们在线程睡眠时打断,此时打断标记为false

为了完成此业务,我们应该在睡眠打断后抛出异常的过程中,再次重置打断标记,也就是置为false,这样我们就能正确停止.

代码如下

    @Slf4j(topic = "c.DoubleInterruptDemo")public class DoubleInterruptDemo {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (true){Thread currentThread = Thread.currentThread();// 判断是否中断if(currentThread.isInterrupted()){log.info("处理后事");break;}try {TimeUnit.SECONDS.sleep(1);log.info("日志监控");} catch (InterruptedException e) {e.printStackTrace();// 重新设置中断状态log.debug("重新设置中断状态");currentThread.interrupt();}}});t1.start();TimeUnit.SECONDS.sleep(4);t1.interrupt();}}

结果如下
在这里插入图片描述

注意一下,介绍一下Thread.interrupted(),这个方法会返回当前线程的打断标记,若为true,将值返回后会自动重新刷新为false.

两阶段终止很好的替代了stop()方法.

过时方法

  • stop(): 停止进程运行,相当于直接杀死进程,这样容易造成死锁,因为可能这个线程拿到了锁的资源,直接杀死导致锁资源没有被释放,别的线程获取不到锁,造成死锁.

  • suspend(): 挂起(暂停)线程运行

  • resume(): 恢复线程运行

    后面两个方法被设计用来暂停和恢复线程的执行,但由于它们的使用不当可能导致线程永远挂起

    假设有两个线程 A 和 B,线程 A 在执行过程中调用了线程 B 的 suspend() 方法来暂停线程 B,然后线程 A 需要在某个条件满足时恢复线程 B,于是调用了线程 B 的 resume() 方法。如果线程 A 在调用 resume() 方法之前被阻塞或结束了,那么线程 B 将永远被挂起,导致死锁

具体原因

  1. 死锁风险:如上例所示,使用 suspend() 和 resume() 容易导致线程之间的死锁,特别是在多线程环境下,线程间的执行顺序难以预测和控制。
  2. 不一致的状态:在线程被 suspend() 暂停时,它可能持有一些重要的资源锁。如果此时其他线程试图访问这些资源,它们将被阻塞,从而导致系统性能下降或死锁。
  3. 难以调试:使用 suspend() 和 resume() 可能导致线程的行为变得难以预测和调试,特别是在复杂的系统中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/42101.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

均匀采样信号的鲁棒Savistky-Golay滤波(MATLAB)

S-G滤波器又称S-G卷积平滑器,它是一种特殊的低通滤波器,用来平滑噪声数据。该滤波器被广泛地运用于信号去噪,采用在时域内基于多项式最小二乘法及窗口移动实现最佳拟合的方法。与通常的滤波器要经过时域-频域-时域变换…

掌握 IPython:灵活运用系统环境变量

掌握 IPython:灵活运用系统环境变量 在数据科学和编程的广阔天地中,IPython 以其强大的交互式功能成为了探索和实验的利器。但你知道吗?IPython 同样能够与系统环境变量进行交互,这使得我们能够更灵活地控制我们的代码和环境。本…

ubuntu22 使用ufw防火墙

专栏总目录 一、安装 sudo apt update sudo apt install ufw 二、启动防火墙 (一)启动命令 sudo ufw enable (二)重启命令 sudo ufw reload 三、配置规则 #允许SSH连接 sudo ufw allow ssh #如果sshd服务端口指定到了8888&a…

Oracle PL / SQL 插入insert

INSERT是SQL的数据操作语言的一部分的SQL关键字之一。 DML可以操作关系数据库中的数据。 让我们从INSERT语句的第一种形式开始,INSERT ... VALUES。 INSERT ... VALUES 以下代码显示如何使用DML的INSERT VALUES子语句。 INSERT INTO authors ( id, name, birth_d…

RedHat运维-LinuxSELinux基础2-文件绑定SELinux上下文

1. 所有资源,比如进程、文件和________,都被打上了SELinux上下文; 2. 所有资源,比如进程、文件和________,都被打上了SELinux上下文; 3. 所有资源,比如进程、文件和________,都被打上…

HTML5使用<blockquote>标签:段落缩进

使用<blockquote>标签可以实现页面文字的段落缩进。这一标签也是每使用一次&#xff0c;段落就缩进一次&#xff0c;并且可以嵌套使用&#xff0c;以达到不同的缩进效果。语法如下&#xff1a; <blockquote>文字</blockquote> 【实例】使用<blockquote&…

常用 Android 反编译工具apktooldex2jarenjarifyjd-guijadx

apktool 官网地址 : https://ibotpeaches.github.io/Apktool/ 反编译命令 : java -jar apktool.jar d demo.apk -o demoapktool d app.apk -r --only-main-classes -o destDird 表示反编译 app.apk 是目标apk文件路径 -r 表示不反编译资源文件 –only-main-classes 表示不反…

【面向就业的Linux基础】从入门到熟练,探索Linux的秘密(十一)-git(3)

Git是目前最流行的版本控制系统之一&#xff0c;在现代软件开发中扮演着重要的角色。它能够有效地跟踪文件变化、协作开发&#xff0c;并存储项目的历史记录。本文的目的是向读者介绍Git的基本概念和工作原理&#xff0c;帮助初学者快速上手使用Git&#xff0c;并帮助有经验的开…

[目标检测]labelme标注数据转yoloV8需要的.txt格式

1、首先需要知道yoloV8目标检测的标签格式&#xff1a; yolov8标签数据格式说明 After using a tool like Roboflow Annotate to label your images, export your labels to YOLO format, with one *.txt file per image (if no objects in image, no *.txt file is required).…

Java.lang.Thread类和Java的主线程

一.Java.lang.Thread类 支持多线程编程 常用方法 二.主线程 ◆Java程序启动时&#xff0c;一个线程立即随之启动&#xff0c;通常称之为程序的主线程 ◆main()方法即为主线程入口 ◆产生其他子线程的线程 ◆必须最后完成执行&#xff0c;因为它执行各种关闭动作 示例 使用…

0-1背包、完全背包算法模板从递归到记忆化搜索到动态规划

0-1背包、完全背包算法模板从递归到记忆化搜索到动态规划 不管是0-1背包还是完全背包&#xff0c;我们都可以将问题转换成为选择或者不选的问题&#xff0c;这个问题在前面的回溯算法模板是一样的。 举个栗子&#xff1a; 假如有1、4、5这三个数&#xff0c;问组成和为12的数需…

202406 CCF-GESP Python 五级试题及详细答案注释

202406 CCF-GESP Python 五级试题及详细答案注释1 单选题(每题 2 分,共 30 分) 第 1 题 在Python中,print((c for c in "GESP"))的输出是( )。 A. (G, E, S, P) B. [G, E, S, P] C. {G, E, S, P} D. 以上选项均不正确答案:D解析:在Python中,(c for c in&q…

Keras实战之图像分类识别

文章目录 整体流程数据加载与预处理搭建网络模型优化网络模型学习率Drop-out操作权重初始化方法对比正则化加载模型进行测试 实战&#xff1a;利用Keras框架搭建神经网络模型实现基本图像分类识别&#xff0c;使用自己的数据集进行训练测试。 问&#xff1a;为什么选择Keras&am…

这门HCIE认证正式发布!

华为认证AI解决方案架构专家HCIE-AI Solution Architect V1.0&#xff08;中文版&#xff09;自2024年6月28日起&#xff0c;正式在中国区发布。 基于“平台生态”战略&#xff0c;围绕“云-管-端”协同的新ICT技术架构&#xff0c;华为公司打造了覆盖ICT领域的认证体系&#x…

C++ | Leetcode C++题解之第217题存在重复元素

题目&#xff1a; 题解&#xff1a; class Solution { public:bool containsDuplicate(vector<int>& nums) {unordered_set<int> s;for (int x: nums) {if (s.find(x) ! s.end()) {return true;}s.insert(x);}return false;} };

2024年江苏省研究生数学建模科研创新实践大赛C题气象数据高精度融合技术研究论文和代码分析

经过不懈的努力&#xff0c; 2024年江苏省研究生数学建模科研创新实践大赛C题气象数据高精度融合技术研究论文和代码已完成&#xff0c;代码为C题全部问题的代码&#xff0c;论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解&#xff08;问题1模型的建…

Go 语言 UUID 库 google/uuid 源码解析:UUID version1 的实现

google/uuid 库地址 关于 UUID 的总体介绍可以查看这篇文章&#xff0c;其包含阅读此篇文章的前置内容。 UUID version 1 在 RFC 4122 文件中定义&#xff0c;其实现基于节点 ID、时钟序列以及当前时间&#xff08;距离格里历改日【1582年10月15日】 的100纳秒数&#xff0c;具…

服务器BMC基础知识总结

前言 因为对硬件方面不太理解&#xff0c;所以打算先从服务器开始学习&#xff0c;也想和大家一起分享一下&#xff0c;有什么不对的地方可以纠正一下哦&#xff01;谢谢啦&#xff01;互相学习共同成长~ 1.BMC是什么&#xff1f; 官方解释&#xff1a;BMC全名Baseboard Mana…

【深度学习】-WASB-调试说明

要改这么几个地方&#xff1a; 代码仓库&#xff1a;/Desktop/code/python_project/WASB-SBDT-main/ 篮球数据集xx_xx_11.xml只保留最后一个11.xml 并把11下直接放置11 video&#xff1a; 这里的东西被我改了&#xff0c;要以仓库为准

SpringSecurity中文文档(Servlet X.509 Run-As)

X.509 Authentication X. 509证书身份验证的最常见用途是在使用 SSL 时验证服务器的身份&#xff0c;最常见的用法是在浏览器中使用 HTTPS。浏览器会自动检查服务器提供的证书是否已由其维护的受信任证书颁发机构列表中的一个颁发(数字签名)。 您还可以使用带有“相互身份验证…