热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

线程常用方法并发编程(Java)

文章目录1、yield2、线程优先级3、join4、sleep5、interrupt6、两阶段终止模式7、park8、守护线程线程常用方法1、yield调用yield使当前线程冲

文章目录

    • 1、yield
    • 2、线程优先级
    • 3、join
    • 4、sleep
    • 5、interrupt
    • 6、两阶段终止模式
    • 7、park
    • 8、守护线程



线程常用方法

1、yield


  1. 调用yield使当前线程冲Running状态转为Runnable状态,让具有相同优先级的其他线程获得运行机会。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
  2. 具体实现依赖于操作系统的调度器

线程对象.yield()

2、线程优先级


  • Java 线程优先级使用 1 ~ 10 的整数表示:
    • 最低优先级 1:Thread.MIN_PRIORITY
    • 最高优先级 10:Thread.MAX_PRIORITY
    • 普通优先级 5(默认优先级):Thread.NORM_PRIORITY
  • 获取线程优先级 :线程对象.getPriority()
  • 设置线程优先级: 先处对象.setPriority()
  • 高优先级的线程比低优先级的线程有更高的几率得到执行,实际上这和操作系统及虚拟机版本相关,有可能即使设置了线程的优先级也不会产生任何作用。

参考文章:Java 多线程:线程优先级

3、join


  • 线程对象.join():无限时同步,当前线程一直等待调用join()方法的线程执行完毕,才继续执行
  • 线程对象.join(long millis):限时同步,最多等待millis毫秒后,当前线程继续执行

private static int r = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {try {Thread.sleep(1000);r = 10;} catch (InterruptedException e) {e.printStackTrace();}});t1.start();log.debug("r = " + r);

结果:r=0,如何让程序打印10呢?想要打印10,主线程必须等待t1线程执行完毕,此时可在打印之前执行t1.join()方法

// 其他代码与上面相同...t1.start();t1.join();log.debug("r = " + r);

当给join设置参数时,结果又会如何呢?

t1.start();
t1.join(100);
log.debug("r = " + r);

结果:r=0

4、sleep

sleep

  1. 调用sleep方法,当前线程从Running状态转为Timed Waiting状态
  2. 其他线程可以执行interrupt方法打断在在睡眠的线程,这时会抛出InterruptedException
  3. 调用sleep方法,当前线程不会释放对象锁标记
  4. 建议使用TimeUnit的sleep代替Thread的sleep来获得更好的可读性

public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (true) {try {Thread.sleep(1000);log.debug("t1 线程执行...");} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();while (true) {TimeUnit.SECONDS.sleep(1);log.debug("主线程执行...");}}

用Thread的sleep方法设置睡眠1s和用TimeUnit的sleep设置睡眠1s,可以很直观的看出后一种的可读性更高。

TimeUnit还可以设置纳秒、微妙、秒、分钟、小时、天等等单位。

5、interrupt


  1. 可以打断正常运行的线程,此时打断标记为true,此时不会清除打断标记(值为true)
  2. 可以打断调用sleep()、wait()、join()等处于阻塞状态的线程,此时会抛出InterruptedException异常;同时会清除打断标记,既打断标志设置为false
  3. 获取打断标记方法isInterrupted(),值为true/false。

@Slf4j(topic = "cm.test01")
public class CMInterrupt {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {log.debug("sleep...");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}});t1.start();Thread.sleep(100);log.debug("interrupt...");t1.interrupt();log.debug("t1 的打断标记:{}", t1.isInterrupted());}
}2021-08-05 20:55:20 DEBUG [Thread-1] cm.test01 - sleep...
2021-08-05 20:55:20 DEBUG [main] cm.test01 - interrupt...
2021-08-05 20:55:20 DEBUG [main] cm.test01 - t1 的打断标记:false
java.lang.InterruptedException: sleep interrupted

在来看下打断正常运行的线程:

@Slf4j(topic = "cm.CMInterruptNormal")
public class CMInterruptNormal {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (true) {}}, "t1");t1.start();Thread.sleep(100);log.debug("interrupt...");t1.interrupt();log.debug("t1 的打断标记:{}", t1.isInterrupted());}
}2021-08-05 21:01:41 DEBUG [main] cm.CMInterruptNormal - interrupt...
2021-08-05 21:01:41 DEBUG [main] cm.CMInterruptNormal - t1 的打断标记:true

线程t1一直在运行,那么当线程被打断了,如果让线程t1停下来呢?此时,可以通过判断标记来结束线程执行。

// 其他代码同上
Thread t1 = new Thread(() -> {while (true) {if (Thread.currentThread().isInterrupted()) break;}}, "t1");

6、两阶段终止模式

一般应用于需要随系统一直执行的某些模块,比如监控模块等。此时,监控模块设置为while(true),监控模块在不需要实施执行时,用sleep()模拟;那么监控模块可以处于2种状态:1、执行正常的监控记录等程序 2、处于睡眠状态。那么当线程被打断时,如何使在可控的情况下结束监控模块,而不影响系统其他模块的运行呢?

图示:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lr95RLtg-1628172174411)(I:\study\java\note\concurrent\phrase2-termination-mode.png)]

代码:

@Slf4j(topic = "cm.CMPhase2terminationMode")
public class CMPhase2terminationMode {public static void main(String[] args) throws InterruptedException {Thread monitor = new Thread(() -> {while (true) {// 判断是否打断if (Thread.currentThread().isInterrupted()) {log.debug("处理善后");break;}try {// 睡眠TimeUnit.SECONDS.sleep(1);// 监控记录log.debug("监控记录执行...");} catch (InterruptedException e) {// 设置打断标记Thread.currentThread().interrupt();e.printStackTrace();}}}, "t1");log.debug("监控模块开始执行...");monitor.start();TimeUnit.MILLISECONDS.sleep(3500);// 模拟意外打断情况monitor.interrupt();log.debug("监控模块关闭...");}
}

如果不在catch模块中添加重新设置打断标记,那么程序就不会结束。

7、park


  1. LockSupport的方法,会让线程无限时暂停执行
  2. interrupt()方法可打断暂停状态,让线程继续执行
  3. 打断标记为true时,park方法不会生效
  4. interrupted()判断打断标记,同时会清除打断标记

代码测试:

@Slf4j(topic = "cm.CMPark")
public class CMPark {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {log.debug("park...");LockSupport.park();log.debug("unpark...");log.debug("线程状态:{}", Thread.currentThread().isInterrupted());LockSupport.park();log.debug("unpark...");});t1.start();TimeUnit.SECONDS.sleep(1);t1.interrupt();}
}2021-08-05 21:50:13.084 DEBUG [Thread-1] cm.CMPark - park...
2021-08-05 21:50:14.083 DEBUG [Thread-1] cm.CMPark - unpark...
2021-08-05 21:50:14.083 DEBUG [Thread-1] cm.CMPark - 线程状态:true
2021-08-05 21:50:14.084 DEBUG [Thread-1] cm.CMPark - unpark...

1秒之后执行打断,当再次执行park的时候,没有生效,此时,可以通过interrupted()方法判断并清除标记

log.debug("unpark...");
log.debug("线程状态:{}", Thread.interrupted());
LockSupport.park();

8、守护线程

Java进程,只有当其所有线程执行结束的时候,才会结束。守护线程,顾名思义,不管守护线程有没有执行完成,当前守护的线程结束的时候,守护线程也会结束执行。

代码示例:

@Slf4j(topic = "cm.CMDaemon")
public class CMDaemon {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (true) {if (Thread.currentThread().isInterrupted()) break;}log.debug("守护线程执行结束...");}, "t1");t1.setDaemon(true);t1.start();TimeUnit.SECONDS.sleep(1);log.debug("主线程执行结束...");}
}

tips:

  1. 如果一个线程要设置为守护线程,通过调用setDaemon(true)方法,一定要在线程启动之前设置,否则无效

推荐阅读
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
author-avatar
无聊人生918_644
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有