Java线程通信

      螣蛇乘雾,终为土灰。

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

一、线程同时执行

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

 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 }

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

二、线程顺序执行

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

 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 }

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

三、线程顺序交叉执行

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

 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 }

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

四、CountDownLatch

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

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

 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 <= 'C'; 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 }

 五、CyclicBarrier 

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

螣蛇乘雾

终为土灰

												

Java线程通信的更多相关文章

  1. 第23章 java线程通信——生产者/消费者模型案例

    第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...

  2. Java 线程通信

    线程通信用来保证线程协调运行,一般在做线程同步的时候才需要考虑线程通信的问题. 1.传统的线程通信 通常利用Objeclt类提供的三个方法: wait() 导致当前线程等待,并释放该同步监视器的锁定, ...

  3. java线程通信与协作小结 多线程中篇(十六)

      在锁与监视器中我们对Object中的方法进行了简单介绍 以监视器原理为核心,三个方法:wait,notify.notifyAll,可以完成线程之间的通信 当然,不会像“语言”似的,有多种多样的沟通 ...

  4. Java线程通信-生产者消费者问题

    线程通信示例——生产者消费者问题 这类问题描述了一种情况,假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费.假设仓库中没有产品,则生产者可以将 产品放入仓库,有 ...

  5. Java线程通信——wait() 和 notify()

    Object类中有关线程通信的方法有两个notify方法和三个wait方法,官方解释: void notify() Wakes up a single thread that is waiting o ...

  6. JAVA线程通信之生产者与消费者

    package cn.test.hf.test3; import java.util.concurrent.locks.Condition;import java.util.concurrent.lo ...

  7. Java线程入门第二篇

    Java线程通信方法 0.(why)每个线程都有自己的栈空间,我们要线程之间进行交流,合作共赢. 1.synchronized和volatile关键字 a)  看下面的synchronized关键字 ...

  8. java多线程-线程通信

    线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 通过共享对象通信 忙等待 wait(),notify()和 notifyAll() 丢失的信号 假唤醒 多线 ...

  9. Java核心知识点学习----使用Condition控制线程通信

    一.需求 实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次. 即:A->B->C---A->B->C---A-> ...

随机推荐

  1. 数据库delete from和truncate删除的区别详解

    一:区别 1.delete from 后面可以直接接条件,truncate不可以 2.delete from 记录是一条条删除的,所删除的每行记录都会进入日志,而truncate一次性删除整个页,因此 ...

  2. Python_time库_特定字符串格式的时间、struct_time、时间戳的处理

    time库 时间戳:格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数. # time.strptime(),功能:将特定字符串格 ...

  3. 记一次对ctf试题中对git文件泄露的漏洞的挖掘

    拿到题,先f12查看代码 发现情况直接进行访问 最后试了发现flag.js可以访问  服务器返回了如下图所示的乱码 很显然有可能是git泄露  话不多说,直接利用https://github.com/ ...

  4. 什么是句柄C#

    话不多说,下面分享下我对句柄的看法. 如果没有意外的话,ABCDE他们将依次进行占用CPU资源.但是可能会发生如下情况 句柄,就是用来维护进程或者系统范围内的一个标识.就比如我们去访问一个文件的时候, ...

  5. Java 实现Https访问工具类 跳过ssl证书验证

    不多BB ,代码直接粘贴可用 import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.F ...

  6. MM32F0020 UART1中断接收

    目录: 1.MM32F0020简介 2.初始化MM32F0020 UART1和NVIC中断 3.编写MM32F0020 UART1中断接收函数 4.编写MM32F0020 UART1发送字节和ASCI ...

  7. 在 Nebula K8s 集群中使用 nebula-spark-connector 和 nebula-algorithm

    本文首发于 Nebula Graph Community 公众号 解决思路 解决 K8s 部署 Nebula Graph 集群后连接不上集群问题最方便的方法是将 nebula-algorithm / ...

  8. Dubbo服务框架和spring-cloud架构的优缺点

    Dubbo一.dubbo简介 Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC实现服务的输出和输入功能,可以和Spring框架无缝集成. Dubbo是一款高性能.轻 ...

  9. Linux-本地日志服务管理(rsyslog基础)

    目录 系统环境 1.常见的两种日志管理服务 1.1 RSYSLOG系统日志服务 1.2 ELK 2.RSYSLOG日志服务的相关知识 2.1 RSYSLOG日志消息级别 2.2 RSYSLOG日志服务 ...

  10. table表格的td行利用css显示...

      默认超过指定长度以...显示, 鼠标放到文本上显示全 代码如下 .fh{ max-width:220px; word-wrap:break-word; text-overflow:ellipsis ...