如何保证三个线程按顺序执行?不会我教你

news/2025/1/11 1:41:49/

👨‍🎓作者:bug菌
✏️博客:CSDN、掘金、infoQ、51CTO等
🎉简介:CSDN|阿里云|华为云|51CTO等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,掘金 | InfoQ | 51CTO等社区优质创作者,全网粉丝合计15w+  ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。

...

✍️温馨提醒:本文字数:1999字, 阅读完需:约 5 分钟

🏆本文收录于《Java进阶实战》,专门攻坚指数提升。

本专栏致力打造最硬核 Spring Boot 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。

小伙伴们在批阅文章的过程中如果觉得文章对您有一丝丝帮助,还请别吝啬您手里的赞呀,大胆的把文章点亮👍吧,您的点赞三连(收藏⭐+关注👨‍🎓+留言📃)就是对bug菌我创作道路上最好的鼓励与支持😘。时光不弃🏃🏻‍♀️,创作不停💕,加油☘️

1. 前言

        哈喽,小伙伴们,你们好呀,今天我们就不整那枯燥无味的知识点了,偶尔换换口味,我们来玩点高级的;由于很多小伙伴都在给我传递一种负面情绪,今年的工作很难找,我就在想是不是八股文没准备充足啊?于是我就在总结高频笔试题,借此想把整理到的笔试题进行集合式的讨论,不仅帮助大家理解,也能帮助自己加深理解,何乐而不为呢。

2. 环境说明

本地的开发环境:

  • 开发工具:IDEA 2021.3
  • JDK版本: JDK 1.8
  • Spring Boot版本:2.3.1 RELEASE
  • Maven版本:3.8.2

3. 题目描述

        现有T1,T2,T3三个线程,请问你如何保证T1,T2,T3三线程按顺序(T1->T2->T3)执行?比如T2 在 T1 执行完后执行,T3 在 T2 执行完后执行.

4. 题目分析

        当你看到这道题,你们的第一反应是什么?反正我首先想到的就是 thread.join()方法,因为既满足题意也是最容易实现的,hh。

        思路1:使用join。不是要保证线程顺序执行嘛,thread.Join()作用就是把指定的线程加入到当前线程中,可以把两个并行执行的线程合并为顺序执行的线程,通俗点讲就是比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会开始执行线程B,以此类推,不就满足了题目要求。

        思路2:使用CountDownLatch。CountDownLatch(闭锁)是一个很有用的工具类,利用它我们可以拦截一个或多个线程使其在某个条件达到后再执行,可设置条件过滤。为什么这题要用它,是因为其内部提供了一个计数器,另外它还提供了一个countDown方法来操作计数器的值,每调用一次countDown方法计数器都会减1,直到计数器的值减为0时就代表条件已达到,所有因调用await方法而阻塞的线程都会被唤醒;这就是CountDownLatch的内部机制,看起来很简单,无非就是阻塞一部分线程让其在达到某个条件之后再执行。

        思路3:使用单个线程池。newSingleThreadExecutor返回以个包含单线程的Executor,将多个任务交给此Exector时,这个线程处理完一个任务后接着处理下一个任务,以此达到顺序执行三个线程的目的。

5. 代码演示

        如下我将上述提供的三种思路进行代码实例演示,希望能辅助大家理解,代码仅供参考,如有疑问,评论区记得踢我,三人行,必有我师焉。

5.1 思路1&代码 

思路1【使用join】代码示例:

public class Test1 {// T1、T2、T3三个线程顺序执行public static void main(String[] args) {Thread t1 = new Thread(new runThread(null));Thread t2 = new Thread(new runThread(t1));Thread t3 = new Thread(new runThread(t2));t1.start();t2.start();t3.start();}static class runThread implements Runnable {//上一个线程private Thread beforeThread;//构造赋值public runThread(Thread beforeThread) {this.beforeThread = beforeThread;}//线程执行。public void run() {//保证第一个线程执行。if (beforeThread != null) {try {//执行join(),合并为顺序执行的线程。beforeThread.join();System.out.println("thread start:" + Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}} else {System.out.println("thread start:" + Thread.currentThread().getName());}}}
}

执行结果截图:

5.2 思路2&代码 

 思路2【使用CountDownLatch】代码示例:

public class Test2 {public static void main(String[] args) {CountDownLatch c1 = new CountDownLatch(0);//计数器为0CountDownLatch c2 = new CountDownLatch(1);//计数器为1CountDownLatch c3 = new CountDownLatch(1);//计数器为1//t1的计数器c1为0,t1执行;t2的计数器减1Thread t1 = new Thread(new runThread(c1, c2));//t2的计数器c2为0时,t2执行;t3的计数器c3减1Thread t2 = new Thread(new runThread(c2, c3));//t3的计数器c3为0时,t3执行.Thread t3 = new Thread(new runThread(c3, c3));t1.start();t2.start();t3.start();}static class runThread implements Runnable {private CountDownLatch c1;private CountDownLatch c2;public runThread(CountDownLatch c1, CountDownLatch c2) {this.c1 = c1;this.c2 = c2;}@Overridepublic void run() {try {//计数为0才可以执行c1.await();System.out.println("thread start:" + Thread.currentThread().getName());//后一线程计数器减少c2.countDown();} catch (InterruptedException e) {e.printStackTrace();}}}
}

执行结果截图:

5.3 思路3&代码  

 思路3【使用单个线程池】代码示例:

public class Test3 {public static void main(String[] args) {final Thread t1 = new Thread(() -> System.out.println("thread start T1:"),"T1");final Thread t2 = new Thread(() -> System.out.println("thread start T2:"),"T2");final Thread t3 = new Thread(() -> System.out.println("thread start T3:"),"T3");//创建一个单线程化的线程池,以此保证线程顺序执行.ExecutorService executor = Executors.newSingleThreadExecutor();//执行线程executor.submit(t1);executor.submit(t2);executor.submit(t3);//关闭线程池executor.shutdown();}
}

执行结果截图:

        综合就是我此次所提供的三种思路,你们会更倾向哪一种实现方式呢?欢迎评论区交流。

        以上三种思路都有各自巧妙之处,对你们而言,还是有很好的借鉴意义,同时也鼓励大家能发挥自己的才能,脑通出更多额解题思路,只要能解题不论方法简单困难,能解题的都是一种突破。

6. 热文推荐🔥

  1. 浅谈你对单例类中使用volatile关键字的理解
  2. Mysql分页 vs Oracle分页 对比分析
  3. Java 如何实现手动连接数据库(MySQL或Oracle)?
  4. Java 如何实现获取客户端公网IP地址?
  5. 为什么print和println输出java对象时会打印内存地址?
  6. 如何解决springboot拦截器@Autowried注入为空问题?
  7. MyBatis中的discriminator鉴别器如何使用?
  8. 如何快速手撕单例类?一文教会你
  9. 如何保证三个线程按顺序执行?不懂我教你
  10. 简谈你对synchronized关键字的使用

7. 最后🔥

🏆本文收录于《Java进阶实战》,需要的小伙伴可以进去瞅瞅。

本专栏致力打造最硬核Java进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。

       我是bug菌,一名CSDN / 阿里云 / 华为云 / 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者,全网粉丝合计10w+,硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!一起学习,一起变强。

关注公众号,获取最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等硬核资源


http://www.ppmy.cn/news/107809.html

相关文章

nodejs 中使用websocket 并且区分空间,实现收到客服端消息 同步给房间内所有连接,小程序中使用websocket,区分房间、空间

❤️砥砺前行,不负余光,永远在路上❤️ 目录 前言一、服务端1、主要是通过nodeexpresswebsocket搭建2、代码大概结构3、nodejs 启动入口文件 引入自己的websocket文件,这里是为了和 http 服务结合起来,将server传入4、websocket.j…

Flutter 笔记 | Flutter 核心原理(三)布局(Layout )过程

布局过程 Layout(布局)过程主要是确定每一个组件的布局信息(大小和位置),Flutter 的布局过程如下: 父节点向子节点传递约束(constraints)信息,限制子节点的最大和最小宽…

【JavaSE】Java基础语法(三十七):Java 中的 String 类(源码级别)

文章目录 1. 构造方法1.1 String()1.2 String(String original)1.3 String(char[] chars)1.4 String(char数组,起始下标,长度)1.5 String(byte数组)1.6 String(byte数组,起始下标,长度)1.7 String(StringBuffer buffer)1.8 String(StringBuilder builder) 2. 普通方法2.1 char …

String、StringBuffer、StringBuilder的区别

1. 可变与不可变 String类中使用字符数组保存字符串,但字符串数组因为有“final”修饰符,所以可以知道string对象是不可变的。又因为类是使用 “final”修饰符,所以字符串创建后不可以对其进行操作。 private final char value[]; private f…

离散数学-集合论

数学基础-离散数学-集合论 集合论是现代各科数学的基础,它起源于十六世纪末期的数集的研究。直到1876-1883年,康托尔发表了一系列有关集合论的文章,奠定了集合论的基础。1904-1908年,策墨罗(Zermelo)提出了集合论的公理系统&…

简谈你对synchronized关键字的使用

👨‍🎓作者:bug菌 ✏️博客:CSDN、掘金、infoQ、51CTO等 🎉简介:CSDN|阿里云|华为云|51CTO等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12…

计划学习网络安全,需要学习哪些知识,应该怎么学习?

虽然现在的网络安全大都是指渗透测试,但是并不代表只有渗透测试这一个方向,除此之外还有二进制逆向这个方向。以下会对这两个方向分别对您进行详解。 渗透测试方向 1、学习编程语言 (1)网站如何搭建的?HTML、CSS、J…

macOS visual studio code 没有读写权限 检查更新报错

问题描述 visual studio code 检查更新,报错,visual studio code没有磁盘读写权限。(可能会导致插件安装报错?) 报错:The application is on a read-only volume. Please move the application and try a…