Java多线程(十五):CountDownLatch,Semaphore,Exchanger,CyclicBarrier,Callable和Future (2)

2,3,4,1,0先获得了permit,相差两秒释放了permit;
5,7,6,9,8获得了permit,相差两秒释放了permit;
因为我们设置的permit是5,所有只能有五个线程获得permit。

Exchanger

Exchanger用来交换两个线程中的数据
示例代码如下

public class MyThread52 extends Thread{ private String str; private Exchanger<String> exchanger; private int sleepSecond; public MyThread52(String str, Exchanger<String> exchanger, int sleepSecond) { this.str = str; this.exchanger = exchanger; this.sleepSecond = sleepSecond; } public void run() { try { System.out.println(this.getName() + "启动, 原数据为" + str + ", 时间为" + new Date()); Thread.sleep(sleepSecond * 1000); str = exchanger.exchange(str); System.out.println(this.getName() + "交换了数据, 交换后的数据为" + str + ", 时间为" + new Date()); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Exchanger<String> exchanger = new Exchanger<String>(); MyThread52 et0 = new MyThread52("111", exchanger, 3); MyThread52 et1 = new MyThread52("222", exchanger, 2); et0.start(); et1.start(); } }

运行结果如下

Thread-1启动, 原数据为222, 时间为Sun Sep 29 22:18:36 CEST 2019 Thread-0启动, 原数据为111, 时间为Sun Sep 29 22:18:36 CEST 2019 Thread-0交换了数据, 交换后的数据为222, 时间为Sun Sep 29 22:18:39 CEST 2019 Thread-1交换了数据, 交换后的数据为111, 时间为Sun Sep 29 22:18:39 CEST 2019

可以看到,数据发生了交换,时间差为最长时间3s。

CyclicBarrier

一组线程等待对方都达到barrier point,再执行接下来的动作,barrier point是循环的,它可以重用。
示例代码如下

public class MyThread53 extends Thread{ private CyclicBarrier cb; private int sleepSecond; public MyThread53(CyclicBarrier cb, int sleepSecond) { this.cb = cb; this.sleepSecond = sleepSecond; } public void run() { try { System.out.println(this.getName() + "运行了"); System.out.println(this.getName() + "准备等待了, 时间为" + new Date()); Thread.sleep(sleepSecond * 1000); cb.await(); System.out.println(this.getName() + "结束等待了, 时间为" + new Date()); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { Runnable runnable = new Runnable() { public void run() { System.out.println("CyclicBarrier的所有线程await()结束了,我运行了, 时间为" + new Date()); } }; //需要等待三个线程await()后再执行runnable CyclicBarrier cb = new CyclicBarrier(3, runnable); MyThread53 cbt0 = new MyThread53(cb, 3); MyThread53 cbt1 = new MyThread53(cb, 6); MyThread53 cbt2 = new MyThread53(cb, 9); cbt0.start(); cbt1.start(); cbt2.start(); } }

运行结果如下

Thread-0运行了 Thread-1运行了 Thread-2运行了 Thread-1准备等待了, 时间为Mon Sep 30 23:02:11 CEST 2019 Thread-2准备等待了, 时间为Mon Sep 30 23:02:11 CEST 2019 Thread-0准备等待了, 时间为Mon Sep 30 23:02:11 CEST 2019 CyclicBarrier的所有线程await()结束了,我运行了, 时间为Mon Sep 30 23:02:20 CEST 2019 Thread-2结束等待了, 时间为Mon Sep 30 23:02:20 CEST 2019 Thread-0结束等待了, 时间为Mon Sep 30 23:02:20 CEST 2019 Thread-1结束等待了, 时间为Mon Sep 30 23:02:20 CEST 2019

Runnable线程在Thread-0,Thread-1,Thread-2 await()后运行,Runnable线程和三个线程的执行时间几乎相同。

Callable和Future

Callable
由于Runnable接口run()返回值是void类型,执行任务后无法返回结果。所以我们需要Callable接口,该接口的call()可以返回值。
Future
Future表示一个异步计算结果,Future提供了如下方法
get():获取任务执行结果
cancel():中断任务
isDone():判断任务是否执行完成
isCancelled():判断任务是否被取消

示例代码如下

public class MyThread54 implements Callable<String> { public String call() throws Exception { System.out.println("进入CallableThread的call()方法, 开始睡觉, 睡觉时间为" + new Date()); Thread.sleep(10000); return "是ss12"; } public static void main(String[] args) throws Exception { ExecutorService es = Executors.newCachedThreadPool(); MyThread54 ct = new MyThread54(); Future<String> f = es.submit(ct); es.shutdown(); Thread.sleep(5000); System.out.println("主线程等待5秒, 当前时间为" + new Date()); String str = f.get(); System.out.println("Future已拿到数据, str = " + str + ", 当前时间为" + new Date()); } }

运行结果如下

进入CallableThread的call()方法, 开始睡觉, 睡觉时间为Sun Nov 03 11:00:22 CET 2019 主线程等待5秒, 当前时间为Sun Nov 03 11:00:27 CET 2019 Future已拿到数据, str = 是ss12, 当前时间为Sun Nov 03 11:00:32 CET 2019

可以看到,Future在10s后拿到了返回结果。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzydgj.html