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

news2025/2/25 23:18:06

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.coloradmin.cn/o/1901860.html

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

相关文章

51单片机STC89C52RC——15.1 AD/DA(模数数模)

目的/效果 1 LCD1602 显示 可调电阻、光敏电阻、热敏电阻值(AD) 2 模拟信号控制LED明暗(DA) 一,STC单片机模块 二,AD/DA 2.1 AD/DA 介绍 AD(Analog to Digital):模拟…

2024年中国十大杰出起名大师排行榜,最厉害的易经姓名学改名字专家

在2024年揭晓的中国十大杰出易学泰斗评选中,一系列对姓名学与国学易经有深入研究的专家荣登榜单。其中,中国十大权威姓名学专家泰斗顶级杰出代表人物的师傅颜廷利大师以其在国际舞台上的卓越贡献和深邃学识,被公认为姓名学及易经起名领域的权…

python库(5):Psutil库实现系统和硬件监控工具

1 psutil简介 psutil(process and system utilities)是一个跨平台库,用于检索运行中进程和系统利用率(包括 CPU、内存、磁盘、网络等)的信息,可以提供丰富的系统监控功能。 2 psutil安装 pip install -i …

『古籍自有答案』古风H5案例赏析

「古籍自有答案」,一部由新京报与字节跳动公益联合打造的古风H5,以诗意盎然的开篇引领用户穿梭于千年文脉。 part1. 创意定位 "人生有惑问先贤,先贤答案存古籍",在这里,每一个灵魂的探问,都能在…

数据库管理工具 -- Navicat Premium v17.0.8 特别版

软件简介 Navicat Premium 是一款功能强大的数据库管理工具,适用于Windows、Mac和Linux平台。它支持多种数据库,包括MySQL、MariaDB、SQL Server、PostgreSQL、Oracle、SQLite等。用户可以通过Navicat Premium轻松地连接到各种数据库服务器,…

【最新整理】全国高校本科及专科招生和毕业数据集(2008-2022年)

整理了各省高校本科、专科招生和毕业数据等21个相关指标,包括招生、在校、毕业人数,以及财政教育支出、教育经费等数据。含原始数据、线性插值、回归填补三个版本,希望对大家有所帮助 一、数据介绍 数据名称:高校本科、专科招生…

mysql在windows下的安装

软件安装 配置环境变量 测试

【十三】图解 Spring 核心数据结构:BeanDefinition 其二

图解 Spring 核心数据结构:BeanDefinition 其二 概述 前面写过一篇相关文章作为开篇介绍了一下BeanDefinition,本篇将深入细节来向读者展示BeanDefinition的设计,让我们一起来揭开日常开发中使用的bean的神秘面纱,深入细节透彻理解…

django之url路径

方式一&#xff1a;path 语法&#xff1a;<<转换器类型:自定义>> 作用&#xff1a;若转换器类型匹配到对应类型的数据&#xff0c;则将数据按照关键字传参的方式传递给视图函数 类型&#xff1a; str: 匹配除了”/“之外的非空字符串。 /test/zvxint: 匹配0或任何…

剖析DeFi交易产品之UniswapV3:交易路由合约

本文首发于公众号&#xff1a;Keegan小钢 SwapRouter 合约封装了面向用户的交易接口&#xff0c;但不再像 UniswapV2Router 一样根据不同交易场景拆分为了那么多函数&#xff0c;UniswapV3 的 SwapRouter 核心就只有 4 个交易函数&#xff1a; exactInputSingle&#xff1a;指…

go语言day10 接口interface 类型断言 type关键字

接口&#xff1a; 空接口类型&#xff1a; 要实现一个接口&#xff0c;就要实现该接口中的所有方法。因为空接口中没有方法&#xff0c;所以自然所有类型都实现了空接口。那么就可以使用空接口类型变量去接受所有类型对象。 类比java&#xff0c;有点像Object类型的概念&#x…

基于YOLOv10+YOLOP+PYQT的可视化系统,实现多类别目标检测+可行驶区域分割+车道线分割【附代码】

文章目录 前言视频效果必要环境一、代码结构1、 训练参数解析2、 核心代码解析1.初始化Detector类2. torch.no_grad()3. 复制输入图像并初始化计数器4. 调用YOLOv10模型进行目标检测5. 提取检测结果信息6. 遍历检测结果并在图像上绘制边界框和标签7. 准备输入图像以适应End-to-…

2024年最新运维面试题(附答案)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号&#xff1a;网络豆云计算学堂 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a; 网络豆的主页​​​​​ 一&#xff0e;选择题 1.HTTP协议默认使用哪个端口…

DolphinScheduler-3.1.9 资源中心实践

前言 目前DolphinScheduler最新的稳定版本是 3.1.9 &#xff0c;基于此做些探索&#xff0c;逐渐深化学习路径&#xff0c;以便于加深理解。 3.2.1 是最新的版本。目前的稳定版本是 3.1.9 基础环境&#xff1a;Hadoop3.3, Java 8, Python3, MacOS14.2.1 一、本地伪分布式安装…

当需要对多个表进行联合更新操作时,怎样确保数据的一致性?

文章目录 一、问题分析二、解决方案三、示例代码&#xff08;以 MySQL 为例&#xff09;四、加锁机制示例五、测试和验证六、总结 在数据库管理中&#xff0c;经常会遇到需要对多个表进行联合更新的情况。这种操作带来了一定的复杂性&#xff0c;因为要确保在整个更新过程中数据…

Linux多进程和多线程(六)进程间通信-共享内存

多进程(六) 共享内存共享内存的创建 示例: 共享内存删除 共享内存映射 共享内存映射的创建解除共享内存映射示例:写入和读取共享内存中的数据 写入: ### 读取: 大致操作流程: 多进程(六) 共享内存 共享内存是将分配的物理空间直接映射到进程的⽤户虚拟地址空间中, 减少数据在…

C++笔试强训2

文章目录 一、选择题二、编程题 一、选择题 和笔试强训1的知识点考的一样&#xff0c;因为输出的是double类型所以后缀为f,m.n对其30个字符所以m是30&#xff0c;精度是4所以n是4&#xff0c;不加符号默认是右对齐&#xff0c;左对齐的话前面加-号&#xff0c;所以答案是-30.4f…

人工智能开发中的数据隐私

人工智能开发中的数据隐私对于建立用户信任和遵守严格法规至关重要。保护敏感信息可确保合乎道德的人工智能使用并防止有害的数据泄露。 为什么在人工智能开发中优先考虑数据隐私至关重要 人工智能的迅猛发展开启了一个前所未有的技术进步时代&#xff0c;彻底改变了各行各业&…

价格预言机的使用总结(一):Chainlink篇

文章首发于公众号&#xff1a;Keegan小钢 前言 价格预言机已经成为了 DeFi 中不可获取的基础设施&#xff0c;很多 DeFi 应用都需要从价格预言机来获取稳定可信的价格数据&#xff0c;包括借贷协议 Compound、AAVE、Liquity &#xff0c;也包括衍生品交易所 dYdX、PERP 等等。…

STL—容器—string类【对其结构和使用的了解】【对oj相关练习的训练】

STL—容器—string类 其实string类准确来说并不是容器&#xff0c;因为他出现的时间比STL要早&#xff0c;但是也可以说是容器吧。 1.为什么要学习string类&#xff1f; 1.1C语言当中的字符串 C语言中&#xff0c;字符串是以’\0’结尾的一些字符的集合&#xff0c;为了操作…