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() {
                @Override
                public void run() {
                    int i = 0;
                    while (true) {
                        System.out.println(Thread.currentThread().getName() + " " + i++);
                    }
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    int i = 0;
                    while (true) {
                        Thread.yield();//让出cpu
                        System.out.println("       "+Thread.currentThread().getName() + " " + i++);
                    }
                }
            });
            //设置优先级,优先级范围为1-10
            t1.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.mfbz.cn/a/779272.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何在PD虚拟机中开启系统的嵌套虚拟化功能?pd虚拟机怎么用 Parallels Desktop 19 for Mac

PD虚拟机是一款可以在Mac电脑中运行Windows系统的应用软件。使用 Parallels Desktop for Mac 体验 macOS 和 Windows 的最优性能,解锁强大性能和无缝交互。 在ParallelsDesktop(PD虚拟机)中如何开启系统的嵌套虚拟化功能?下面我们…

vulhub-activemq(CVE-2015-5254)

Apache ActiveMQ 5.13.0版本之前到5.x版本的安全漏洞,该程序引起的漏洞不限制代理中可以序列化的类。远程攻击者可以制作一个特殊的序列化 Java 消息服务 (JMS) ObjectMessage 对象,利用该漏洞执行任意代码。 Apache ActiveMQ 5.x ~ Apache ActiveMQ 5.1…

【人工智能】-- 智能机器人

个人主页:欢迎来到 Papicatch的博客 课设专栏 :学生成绩管理系统 专业知识专栏: 专业知识 文章目录 🍉引言 🍉机器人介绍 🍈机器人硬件 🍍机械结构 🍍传感器 🍍控…

基于Android Studio电影购票系统

目录 项目介绍 图片展示 运行环境 获取方式 项目介绍 主要实为了方便用户随时随地进行电影购票。在配色方面选择了一些富有电影元素的颜色。主要能够实现的功能与流程为: 1.用户首先需要注册用户名填写密码。 2.用户可以用之前注册的用户名和密码进行登录。 3.登…

键盘异常的检测与解决方案

今天对象用Word写文档,按下Ctrl的时候,页面不停地上下滑动,导致无法正常编辑文本。 重启之后,仍然无法解决,推断是键盘坏了。 但是当按下Fn或其他功能键,焦点移除,页面就不会再抖动了。 现在…

[CP_AUTOSAR]_分层软件架构_内容详解

目录 1、软件分层内容1.1、Microcontroller Abstraction Layer1.2、ECU Abstraction Layer1.2.1、I/O HW Abstraction1.2.2、Communication Hardware Abstraction1.2.3、Memory Hardware Abstraction1.2.4、Onboard Device Abstraction1.2.5、Crypto Hardware Abstraction 1.3、…

Docker安装遇到问题:curl: (7) Failed to connect to download.docker.com port 443: 拒绝连接

问题描述 首先,完全按照Docker官方文档进行安装: Install Docker Engine on Ubuntu | Docker Docs 在第1步:Set up Dockers apt repository,执行如下指令: sudo curl -fsSL https://download.docker.com/linux/ubu…

超赞的8款生活APP推荐!

AI视频生成:小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/每天都会有几十个应用程序发布,一款用得好的应用程序可以极大地丰富您的生活。对于那些不知道哪个应用程序适合您以及您需要哪个应用程…

将excel表格转换为element table(下)

在‘将excel表格转换为element table(上)’我们把excel 转换后通过数据重构绑定到了element table上,现在要做的就是根据源文件进行行列进行合并操作 先看看最终处理的结果 这里在一步步分析实现步骤。 先分析一下合并的逻辑 大致思路理理如上。 思路有了接下来…

微信小程序的农产品商城-计算机毕业设计源码46732

摘 要 随着社会经济的发展和人们消费观念的升级,农产品电商行业逐渐壮大。但传统的农产品销售模式存在信息不透明、中间环节复杂等问题,而微信小程序作为一种便捷的移动应用平台,为农产品商城的建设提供了新的可能性。通过微信小程序的设计与…

上位机图像处理和嵌入式模块部署(mcu项目1:用户手册)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 一个完整的产品,除了上位机软件、固件、硬件、包装之外,一般还需要一个用户手册。好的用户手册应该能够兼顾到大多数人的认…

开发个人Go-ChatGPT--1 项目介绍

开发个人Go-ChatGPT--1 项目介绍 开发个人Go-ChatGPT--1 项目介绍知识点大纲文章目录项目地址 开发个人Go-ChatGPT–1 项目介绍 本文将以一个使用Ollama部署的ChatGPT为背景,主要还是介绍和学习使用 go-zero 框架,开发个人Go-ChatGPT的服务器后端&#x…

电脑为什么会提示丢失msvcp140.dll?怎么修复msvcp140.dll文件会靠谱点

电脑为什么会提示丢失msvcp140.dll?其实只要你的msvcp140.dll文件一损坏,然而你的电脑程序需要运用到这个msvcp140.dll文件的时候,就回提示你丢失了msvcp140.dll文件!因为没有这个文件,你的很多程序都用不了的。今天我…

Redis基础教程(十三):Redis lua脚本

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 💝&#x1f49…

[240706] 史蒂夫·乔布斯近40年前就预言了苹果智能 | Globalping 用于网络诊断和性能测试的命令行工具

目录 史蒂夫.乔布斯近40年前就预言了苹果智能Globalping 用于网络诊断和性能测试的命令行工具功能1. Ping2. Traceroute3. DNS 查询4. HTTP 请求 使用场景1. 网络性能监测2. 故障排除3. 网站性能优化4. 服务可用性监控 优势1. [全球覆盖](https://www.jsdelivr.com/network)2. …

[Vite]Vite插件生命周期了解

[Vite]Vite插件生命周期了解 Chunk和Bundle的概念 Chunk: 在 Vite 中,chunk 通常指的是应用程序中的一个代码片段,它是通过 Rollup 或其他打包工具在构建过程中生成的。每个 chunk 通常包含应用程序的一部分逻辑,可能是一个路由视…

5个实用的文章生成器,高效输出优质文章

在自媒体时代,优质内容的持续输出是吸引读者、提升影响力的关键。然而,对于许多自媒体创作者来说,频繁的创作难免会遭遇灵感枯竭、创作不出文章的困扰。此时,文章生成器便成为了得力的助手。文章生成器的优势能够快速自动生成高质…

C++怎么解决不支持字符串枚举?

首先,有两种方法:使用命名空间和字符串常量与使用 enum class 和辅助函数。 表格直观展示 特性使用命名空间和字符串常量使用 enum class 和辅助函数类型安全性低 - 编译器无法检查字符串有效性,运行时发现错误高 - 编译期类型检查&#xf…

SCI论文发表:构建清晰论文框架的10个原则 (附思维导图,建议收藏)

我是娜姐 迪娜学姐 ,一个SCI医学期刊编辑,探索用AI工具提效论文写作和发表。 论文框架是什么?对我们完成一篇论文有哪些作用? 之前娜姐分享过一篇深圳湾实验室周耀旗教授关于论文写作的文章,他提出的第一个重要原则就…

Linux笔记之二

Linux笔记之二 一、文件属性学习二、软链接和硬链接1.软链接2.硬链接 三、Vim编辑器四、账号管理总结 一、文件属性学习 Linux 系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。为了保护系统的安全性,Linux系统对不同…