一般而言,如果没有干预的话,线程在启动之后会一直运行到结束,但有时候我们又需要很多线程来共同完成一个任务,这就牵扯到线程间的通讯。

如何让两个线程先后执行?Thread.join方法

private static void demo2() {
Thread A = new Thread(new Runnable() {
@Override
public void run() {
printNumber("A");
}
});
Thread B = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("B starts waiting for A");
try {
A.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
printNumber("B");
}
});
B.start();
A.start();
}

其中A.join()的意思即是等待A线程执行完毕。

如何让两个线程交互执行?object.wait和object.notify方法

 /**
* A 1, B 1, B 2, B 3, A 2, A 3
*/
private static void demo3() {
Object lock = new Object();
Thread A = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println("A 1");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A 2");
System.out.println("A 3");
}
}
});
Thread B = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println("B 1");
System.out.println("B 2");
System.out.println("B 3");
lock.notify();
}
}
});
A.start();
B.start();
}

A在输出完1之后等待B的notify才会去执行其他的操作。

如何让四个线程的其中一个等待其他三个执行完毕?CountdownLatch就是干这个的。

CountdownLatch的基本用法

  1. 创建一个CountdownLatch并赋初始值,CountdownLatch countDownLatch = new CountDownLatch(3;
  2. 在需要等待的线程中调用 countDownLatch.await() 进入等待状态;
  3. 在其他线程执行中适当的时候调用 countDownLatch.countDown() ,会使内部否计数值减一;
  4. 当 countDown()导致count值为 0, 则处于等待态的线程开始执行。
 private static void runDAfterABC() {
int worker = 3;
CountDownLatch countDownLatch = new CountDownLatch(worker);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("D is waiting for other three threads");
try {
countDownLatch.await();
System.out.println("All done, D starts working");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
for (char threadName='A'; threadName <= 'C'; threadName++) {
final String tN = String.valueOf(threadName);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(tN + "is working");
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(tN + "finished");
countDownLatch.countDown();
}
}).start();
}
}

如何让三个线程的各自开始做一些事情,然后在某个时间点上进行同步?CyclicBarrier 是干这个的。

CyclicBarrier 的用法:

  1. 首先还是需要先创建一个CyclicBarrier对象,设置初始值,CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
  2. 各个线程同步启动,在完成一些逻辑之后,调用 cyclicBarrier.await()开始等待;
  3. 当所有的线程都调用了 cyclicBarrier.await() 之后,每个线程都可以执行之后的逻辑。
 private static void runABCWhenAllReady() {
int runner = 3;
CyclicBarrier cyclicBarrier = new CyclicBarrier(runner);
final Random random = new Random();
for (char runnerName='A'; runnerName <= 'C'; runnerName++) {
final String rN = String.valueOf(runnerName);
new Thread(new Runnable() {
@Override
public void run() {
long prepareTime = random.nextInt(10000) + 100;
System.out.println(rN + "is preparing for time:" + prepareTime);
try {
Thread.sleep(prepareTime);
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.println(rN + "is prepared, waiting for others");
cyclicBarrier.await(); // The current runner is ready, waiting for others to be ready
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(rN + "starts running"); // All the runners are ready to start running together
}
}).start();
}
}

如何取回某个线程的返回值了?Callable 是干这个的。

先看下定义:

@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}

然后直接给个例子:

 private static void doTaskWithResultInWorker() {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("Task starts");
Thread.sleep(1000);
int result = 0;
for (int i=0; i<=100; i++) {
result += i;
}
System.out.println("Task finished and return result");
return result;
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
try {
System.out.println("Before futureTask.get()");
System.out.println("Result:" + futureTask.get());
System.out.println("After futureTask.get()");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}

注意,其中futureTask.get()方法是阻塞调用。

以上都是一些很基本的应用,在新版本的CompleteFuture中其实提供了更多的链式操作,不过写起来比较复杂,看起来也不清晰。

如何在java中实现跨线程的通讯的更多相关文章

  1. 如何在Java中编写一个线程安全的方法?

    线程安全总是与多线程有关的,即一个线程访问或维护数据时遭到了其它线程的“破坏”,为了不被破坏,就要保持所维护变量的原子性: 1 局部变量总是线程安全的,因为每个线程都有自己的栈,而在方法中声明的变量都 ...

  2. 用代码说话:如何在Java中实现线程

    并发编程是Java语言的重要特性之一,"如何在Java中实现线程"是学习并发编程的入门知识,也是Java工程师面试必备的基础知识.本文从线程说起,然后用代码说明如何在Java中实现 ...

  3. 如何在Java中测试类是否是线程安全的

    通过优锐课的java核心笔记中,我们可以看到关于如何在java中测试类是否线程安全的一些知识点汇总,分享给大家学习参考. 线程安全性测试与典型的单线程测试不同.为了测试一个方法是否是线程安全的,我们需 ...

  4. 『动善时』JMeter基础 — 38、JMeter中实现跨线程组关联

    目录 1.JMeter中实现跨线程组关联说明 (1)JMeter中实现跨线程组关联步骤 (2)测试计划内包含的元件 2.用户登陆请求的相关操作 (1)进行登陆操作获取Cookie信息 (2)把Cook ...

  5. Java 中如何实现线程间通信

    世界以痛吻我,要我报之以歌 -- 泰戈尔<飞鸟集> 虽然通常每个子线程只需要完成自己的任务,但是有时我们希望多个线程一起工作来完成一个任务,这就涉及到线程间通信. 关于线程间通信本文涉及到 ...

  6. 如何在JAVA中实现一个固定最大size的hashMap

    如何在JAVA中实现一个固定最大size的hashMap 利用LinkedHashMap的removeEldestEntry方法,重载此方法使得这个map可以增长到最大size,之后每插入一条新的记录 ...

  7. 如何在java中使用sikuli进行自动化测试

    很早之前写过一篇介绍sikuli的文章.本文简单介绍如何在java中使用sikuli进自动化测试. 图形脚本语言sikuli sikuli IDE可以完成常见的单击.右击.移动到.拖动等鼠标操作,ja ...

  8. Java中的守护线程 & 非守护线程(简介)

    Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...

  9. c#中如何跨线程调用windows窗体控件

    c#中如何跨线程调用windows窗体控件?   我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍.首 ...

随机推荐

  1. sourcetree的安装及使用

    sourcetree下载地址:https://www.sourcetreeapp.com/ 点击安装包安装 此前需要跳转到bitbucket登录,我没有账号,所以我直接跳转到到https://bitb ...

  2. pentestbox更新msf

    pentestbox成功升级msf 1.  输入 msfupdate 进行软件更新 2.  在[*] Updating gems...,软件报错,提示找不到文件路径,输入以下两条命令,尝试单独安装 g ...

  3. SSM-CRUD入门项目——修改与PUT请求

    修改 分析: 点击编辑,弹出用户修改的模态框,    模态框中显示用户的信息,    点击更新完成修改! 第一步先复制添加员工的模态框进行修改调整,完成修改员工的模态框的创建:(当然,相应的生成员工数 ...

  4. 2017-2018-1 20155318《信息安全技术》实验二——Windows口令破解

    2017-2018-1 20155318<信息安全技术>实验二--Windows口令破解 一.实验原理 口令破解方法 口令破解主要有两种方法:字典破解和暴力破解. 字典破解是指通过破解者对 ...

  5. plsql高级查询命令

    一.DDL数据定义语言:表操作 1.新建表 SQL> create table good(id number,name varchar2(10)); 添加注释 SQL> comment o ...

  6. 1150: [CTSC2007]数据备份Backup

    1150: [CTSC2007]数据备份Backup https://lydsy.com/JudgeOnline/problem.php?id=1150 分析: 堆+贪心. 每次选最小的并一定是最优的 ...

  7. C#:通过NuGet程序包下载CefSharp来加载谷歌浏览器

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 首先我讲明一下我要做的,公司有个C# wpf的项目需要我把一个开发好的网页嵌入到客户端当中,由于种种原因,我放 ...

  8. mysql学习----支持Emoji表情

    但发现了一个问题,iPhone上有Emoji表情,插入Mysql时失败了,报如下异常: java.sql.SQLException: Incorrect string value: '\xF0\x9F ...

  9. Python不生成HTMLTestRunner报告-转载学习

    1.问题:Python中同一个.py文件中同时用unittest框架和HtmlReport框架后,HtmlReport不被执行. 2.为什么?其实不是HtmlReport不被执行,也不是HtmlRep ...

  10. xampp服务器搭建和使用

    1.安装完XAMPP后会出现Apache端口被占用的问题,一下方法解决 错误信息如下: Error: Apache shutdown unexpectedly. 9:37:01  [Apache] T ...