Java线程通信

Java线程通信

螣蛇乘雾,终为土灰。

多个线程协同工作完成某个任务时就会涉及到线程间通信问题。如何使各个线程之间同时执行,顺序执行、交叉执行等。

一、线程同时执行

创建两个线程a和b,两个线程内调用同一个打印 1-3 三个数字的方法。

Java线程通信Java线程通信
1 package tjt;
 2
 3 import java.time.LocalDate;
 4
 5 public class Test {
 6
 7     /**
 8      * 创建两个线程a和b,两个线程内调用同一个打印 1-3 三个数字的方法。
 9      */
10     private static void situationOne() {
11         Thread a = new Thread(new Runnable() {
12             @Override
13             public void run() {
14                 doSomething("a");
15             }
16         });
17         Thread b = new Thread(new Runnable() {
18             @Override
19             public void run() {
20                 doSomething("b");
21             }
22         });
23         a.start();
24         b.start();
25     }
26
27     /**
28      * 依次打印 1, 2, 3 三个数字
29      *
30      * @param threadName
31      */
32     private static void doSomething(String threadName) {
33         int i = 0;
34         while (i++ < 3) {
35             try {
36                 Thread.sleep(200);
37             } catch (InterruptedException e) {
38                 e.printStackTrace();
39             }
40             System.out.println(LocalDate.now() + " Thread " + threadName + " is doing, printing: " + i);
41         }
42     }
43
44     public static void main(String[] args) {
45         situationOne();
46     }
47 }

View Code

多次运行发现a和b是同时打印的,无执行顺序可言。

Java线程通信

二、线程顺序执行

创建两个线程a和b,要求b 在 a 全部打印完后再开始打印。使用 thread.join() 方法,在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行,即必须a执行完毕后才轮到b。

Java线程通信Java线程通信
1 package tjt;
 2
 3 import java.time.LocalDate;
 4
 5 public class Test {
 6
 7     /**
 8      * 创建两个线程a和b,要求b 在 a 全部打印完后再开始打印,使用 thread.join() 方法。
 9      * 保证线程a执行完毕后才轮到b
10      */
11     private static void situationOne() {
12         Thread a = new Thread(new Runnable() {
13             @Override
14             public void run() {
15                 doSomething("a");
16             }
17         });
18         Thread b = new Thread(new Runnable() {
19             @Override
20             public void run() {
21                 try {
22                     System.out.println("线程 b 正在通过thread.join()等待线程 a 执行完毕后再润");
23                     // thread.join() 在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行,即必须a执行完毕后才轮到b
24                     a.join();
25                 } catch (InterruptedException e) {
26                     e.printStackTrace();
27                 }
28                 doSomething("b");
29             }
30         });
31         a.start();
32         b.start();
33     }
34
35     /**
36      * 依次打印 1, 2, 3 三个数字
37      *
38      * @param threadName
39      */
40     private static void doSomething(String threadName) {
41         int i = 0;
42         while (i++ < 3) {
43             try {
44                 Thread.sleep(200);
45             } catch (InterruptedException e) {
46                 e.printStackTrace();
47             }
48             System.out.println(LocalDate.now() + " Thread " + threadName + " is doing, printing: " + i);
49         }
50     }
51
52     public static void main(String[] args) {
53         situationOne();
54     }
55 }

View Code

无论运行多少次,都是线程a先执行完毕再到线程b。

Java线程通信

三、线程顺序交叉执行

创建两个线程a和b,要求 a 在打印完 1 后,再让 b 打印 1、2、 3,接着再回到 a 继续打印 2、3。如此顺序交叉执行仅靠 Thread.join() 是无法满足需求的,需要更细粒度的锁来控制执行顺序,以及object.wait() 和 object.notify() 两个方法来实现。

Java线程通信Java线程通信
1 package tjt;
 2
 3 import java.time.LocalDate;
 4
 5 public class TestAgain {
 6
 7     private static void situationTwo() {
 8         // a 和 b 的共享对象锁 lock
 9         Object lock = new Object();
10         Thread a = new Thread(new Runnable() {
11             @Override
12             public void run() {
13                 // 同步锁 lock
14                 synchronized (lock) {
15                     // a 获得锁后执行
16                     doSomething("a", 1);
17                     try {
18                         // 调用 lock.wait() 方法,交出锁的控制权,进入 wait 状态,等待notify唤醒
19                         lock.wait();
20                     } catch (InterruptedException e) {
21                         e.printStackTrace();
22                     }
23                     doSomething("a", 2);
24                     doSomething("a", 3);
25                 }
26             }
27         });
28         Thread b = new Thread(new Runnable() {
29             @Override
30             public void run() {
31                 // 同步锁 lock
32                 synchronized (lock) {
33                     // a 获得锁后执行
34                     doSomething("b", 1);
35                     doSomething("b", 2);
36                     doSomething("b", 3);
37                     // 调用 lock.notify() 方法,唤醒正在 wait 的线程 a
38                     lock.notify();
39                 }
40             }
41         });
42         a.start();
43         b.start();
44     }
45
46     /**
47      * 打印
48      *
49      * @param threadName
50      * @param num
51      */
52     private static void doSomething(String threadName, int num) {
53         System.out.println(LocalDate.now() + " Thread " + threadName + " is doing, printing: " + num);
54     }
55
56     public static void main(String[] args) {
57         situationTwo();
58     }
59 }

View Code

无论运行多少次,都是线程a先执行打印1,然后线程b执行打印1、2、3,最后线程a执行打印2、3。

Java线程通信

四、CountDownLatch

CountDownLatch 计数器适用于一个线程去等待多个线程的情况。例如A B C 三个线程同时运行,各自独立运行完后通知线程 D 执行,就可以利用 CountdownLatch 来实现这类通信方式。

对比之前的join方法,thread.join()可以让一个线程等另一个线程运行完毕后再继续执行,其可以在 D 线程里依次 join A B C,但这样 A B C 必须依次执行,无法实现ABC三者能同步运行。

Java线程通信Java线程通信
1 package tjt;
 2
 3 import java.time.LocalDate;
 4 import java.util.concurrent.CountDownLatch;
 5
 6 public class TestCountDownLatch {
 7
 8     /**
 9      * countDownLatch 适用于一个线程去等待多个线程的情况
10      * 四个线程A、B、C、D,
11      * 其中 D 要等到 A B C 全执行完毕后才执行,且 A B C 是同步运行的,即ABC无顺序执行
12      */
13     private static void situationThree() {
14         // 初始计数值设置为3,即总共四个线程A、B、C、D
15         CountDownLatch latch = new CountDownLatch(3);
16         new Thread(new Runnable() {
17             @Override
18             public void run() {
19                 System.out.println(LocalDate.now() + "线程 D 等待线程A B C 执行完毕后才可执行");
20                 try {
21                     // await() 检查计数器值是否为 0,若不为 0 则保持等待状态
22                     latch.await();
23                     // 其他线程 的 countDown() 方法把计数值变成 0 时,等待线程里的 countDownLatch.await() 立即退出,继续执行下面的代码
24                     System.out.println(LocalDate.now() + "线程A B C 执行完毕,轮到线程D 执行了,当前latch:" + latch.getCount());
25                 } catch (InterruptedException e) {
26                     e.printStackTrace();
27                 }
28             }
29         }).start();
30
31         // 循环执行线程 A B C
32         for (char threadName = 'A'; threadName ) {
33             String name = String.valueOf(threadName);
34             new Thread(new Runnable() {
35                 @Override
36                 public void run() {
37                     System.out.println("线程 " + name + " is running");
38                     // countDown(),将倒计数器减 1, 计数器被减至 0 时立即触发D 的 await()
39                     try {
40                         Thread.sleep(200);
41                     } catch (InterruptedException e) {
42                         e.printStackTrace();
43                     }
44                     System.out.println("线程 " + name + " 执行完毕计数器");
45                     latch.countDown();
46                 }
47             }).start();
48         }
49     }
50
51     public static void main(String[] args) {
52         situationThree();
53     }
54
55 }

View Code

Java线程通信

五、CyclicBarrier

实现线程间互相等待,可以利用 CyclicBarrier 栅栏。CountDownLatch 可以用来倒计数,但当计数完毕,只有一个线程的 await() 会得到响应,无法让多个线程同时触发。如要求线程 A B C 各自开始准备,直到三者都准备完毕再同时运行其就无法满足需求,而用CyclicBarrier则完全OK。

螣蛇乘雾

终为土灰

undefined

Original: https://www.cnblogs.com/taojietaoge/p/15997641.html
Author: 涛姐涛哥
Title: Java线程通信

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/611571/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • SpringCloudAlibaba 实战

    SpringCloudAlibaba 实战 服务发现Nacos 服务发现原理 负载均衡Ribbon 细粒度修改Ribbon负载均衡规则 指定Ribbon全局负载均衡规则 配置Rib…

    数据库 2023年6月6日
    0109
  • IDEA 常用插件

    插件使用参考:Idea插件系列 插件名称 说明 IDE Eval Reset 破解软件 Alibaba Java Coding Guidelines 阿里巴巴开发规范 tabnin…

    数据库 2023年6月6日
    087
  • 第十五章 Spring动态代理开发

    创建原始对象 public class UserServiceImpl implements UserService{ @Override public void register…

    数据库 2023年6月14日
    0107
  • javaWeb知识点大集合!!!

    pom文件: 4.0.0 org.example javaweb_maven 1.0-SNAPSHOT war UTF-8 1.7 1.7 com.github.pagehelpe…

    数据库 2023年6月16日
    083
  • django-nginx与uwsgi项目部署

    uwsgi是提供动态服务的 nginx反向代理 在项目中创建一个settings.py的副本。我这里重命名为copy_settings.py,将配置文件中的DEBUG=False …

    数据库 2023年6月6日
    0101
  • Java学习-第一部分-第二阶段-项目实战:坦克大战【2】

    坦克大战【2】 笔记目录:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 线程-应用到坦克大战 坦克大战0.3版 陆游曾说…

    数据库 2023年6月11日
    095
  • 力扣数据库题目176第二高的薪水

    力扣数据库题目176第二高的薪水 题目 编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) 。 +—-+——&#8…

    数据库 2023年6月9日
    097
  • Redis的五大数据类型(简单使用)

    redis是基于内存的,内存的读写速度非常快 ; redis是单线程的,省去了很多上下文切换线程的时间; *redis因为是基于内存的 不涉及io操作 所以单线程效率是最高的 回归…

    数据库 2023年6月6日
    094
  • proxySQL with SemiSync

    配置读写分离 先查看一下规则表的表结构 https://github.com/sysown/proxysql/wiki/Main-(runtime)#mysql_query_rul…

    数据库 2023年6月16日
    082
  • python: can’t open file ‘upload.py’: [Errno 2] No such file or directory

    为了发博客方便,参考别人的文章(见参考文章:[1][2]),使用 Metaweblog 和 pycnblog([3])插件实现相关功能,将本地markdown文件同步至博客园。使用…

    数据库 2023年6月14日
    085
  • 2022-08-15 – 初识MySQL

    MySQL数据库 数据库 数据库,又称为Database,简称DB。数据库就是一个文件集合。顾名思义:是一个存储数据的仓库,实际上就是一堆文件,这些文件中存储了具有特定格式的数据,…

    数据库 2023年5月24日
    071
  • MySQL数据库的创建、删除和备份

    总结MySQL数据库的创建、删除和备份操作 MySQL数据库的创建、删除和备份 数据库的创建 //使用指令创建数据库 CREATE DATABASE yjh_db01; //创建一…

    数据库 2023年6月16日
    082
  • 记一次生产事故,Redis内存问题排查与解决

    前几天生产的Redis突然挂掉了,之前都没有太注意过Redis那边的使用情况,这次Redis挂掉重启后,发现在那台服务器上,Redis占用了足足30G的运行内存,这才意识到Redi…

    数据库 2023年6月6日
    087
  • TypeScript语言基础

    一、什么是TypeScript 编程语言包括动态类型语言和静态类型语言。动态类型语言是指在程序运行阶段才检查变量数据类型的语言,在定义变量时不需要指定变量的数据类型,通常在编译时不…

    数据库 2023年6月14日
    095
  • 设计模式之简单工厂

    一、简单工厂:为了客户类和服务类之间的解耦,把对象的创建任务交给第三方类,这个第三方类就充当工厂的作用,严格来说简单工厂不属于23种设计模式之一。 二、实现思路 :创建一个简单工厂…

    数据库 2023年6月14日
    085
  • Gorm 的黑魔法

    开发过程中,看到同事的代码写了这么一段: db = db.Session(&gorm.Session{Context: db.Statement.Context}).Fir…

    数据库 2023年6月9日
    096
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球