Java多线程(十五):CountDownLatch,Semaphore,Exchanger,CyclicBarrier,Callable和Future
2019-11-18杂谈搜奇网35°c
A+ A-CountDownLatch
CountDownLatch用来使一个线程或多个线程守候到其他线程完成。CountDownLatch有个初始值count,await要领会壅塞线程,直到经由过程countDown要领挪用使count削减为0才会实行await要领背面的代码。
示例代码
MyThread50_0是WorkThread,差别的线程休眠时候不一样。
public class MyThread50_0 extends Thread
{
private CountDownLatch cdl;
private int sleepSecond;
public MyThread50_0(String name, CountDownLatch cdl, int sleepSecond)
{
super(name);
this.cdl = cdl;
this.sleepSecond = sleepSecond;
}
public void run()
{
try
{
System.out.println(this.getName() + "启动了,时候为" + new Date());
Thread.sleep(sleepSecond * 1000);
cdl.countDown();
System.out.println(this.getName() + "实行完了,时候为" + new Date());
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
MyThread50_1是DoneThread和main要领
public class MyThread50_1 extends Thread {
private CountDownLatch cdl;
public MyThread50_1(String name, CountDownLatch cdl)
{
super(name);
this.cdl = cdl;
}
public void run()
{
try
{
System.out.println(this.getName() + "要守候了, 时候为" + new Date());
cdl.await();
System.out.println(this.getName() + "守候完了, 时候为" + new Date());
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public static void main(String[] args) {
CountDownLatch cdl = new CountDownLatch(3);
MyThread50_1 dt0 = new MyThread50_1("DoneThread1", cdl);
MyThread50_1 dt1 = new MyThread50_1("DoneThread2", cdl);
dt0.start();
dt1.start();
MyThread50_0 wt0 = new MyThread50_0("WorkThread1", cdl, 2);
MyThread50_0 wt1 = new MyThread50_0("WorkThread2", cdl, 3);
MyThread50_0 wt2 = new MyThread50_0("WorkThread3", cdl, 4);
wt0.start();
wt1.start();
wt2.start();
}
}
运转效果以下
DoneThread2要守候了, 时候为Sun Sep 22 21:37:57 CEST 2019
DoneThread1要守候了, 时候为Sun Sep 22 21:37:57 CEST 2019
WorkThread3启动了,时候为Sun Sep 22 21:37:57 CEST 2019
WorkThread2启动了,时候为Sun Sep 22 21:37:57 CEST 2019
WorkThread1启动了,时候为Sun Sep 22 21:37:57 CEST 2019
WorkThread1实行完了,时候为Sun Sep 22 21:37:59 CEST 2019
WorkThread2实行完了,时候为Sun Sep 22 21:38:00 CEST 2019
WorkThread3实行完了,时候为Sun Sep 22 21:38:01 CEST 2019
DoneThread2守候完了, 时候为Sun Sep 22 21:38:01 CEST 2019
DoneThread1守候完了, 时候为Sun Sep 22 21:38:01 CEST 2019
“DoneThreadX要守候了”和“WorkThreadX启动了”的递次是随机的。
“WorkThreadX实行完了“的递次根据1、2、3,因为我们的守候时候2、3、4秒。
待WorkThread3实行完了,才会实行await()以后的代码,DoneThreadX实行完了,一样该递次随机。
这是一种加强版的守候/关照模子,它能够完成多个事情线程完成使命后关照多个守候线程最先事情。
我们之前的守候/关照模子只能完成一个事情线程完成使命后关照一个守候线程或许一切守候线程最先事情。
Semaphore
Semaphore用来掌握并发数目,Semaphore组织函数传入permit(允许),一个permit相当于一个不可重入锁,acquire要领取得permit,relase要领送还permit。
代码示例以下
public class MyThread51 {
public static void main(String[] args)
{
final Semaphore semaphore = new Semaphore(5);
Runnable runnable = new Runnable()
{
public void run()
{
try
{
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "取得了permit,时候为" + new Date());
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "释放了permit,时候为" + new Date());
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
semaphore.release();
}
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++)
threads[i] = new Thread(runnable);
for (int i = 0; i < threads.length; i++)
threads[i].start();
}
}
运转效果以下
Thread-2取得了permit,时候为Sun Sep 29 21:47:05 CEST 2019
Thread-3取得了permit,时候为Sun Sep 29 21:47:05 CEST 2019
Thread-4取得了permit,时候为Sun Sep 29 21:47:05 CEST 2019
Thread-1取得了permit,时候为Sun Sep 29 21:47:05 CEST 2019
Thread-0取得了permit,时候为Sun Sep 29 21:47:05 CEST 2019
Thread-3释放了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-1释放了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-0释放了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-2释放了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-4释放了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-5取得了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-7取得了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-6取得了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-9取得了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-8取得了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-5释放了permit,时候为Sun Sep 29 21:47:09 CEST 2019
Thread-8释放了permit,时候为Sun Sep 29 21:47:09 CEST 2019
Thread-9释放了permit,时候为Sun Sep 29 21:47:09 CEST 2019
Thread-6释放了permit,时候为Sun Sep 29 21:47:09 CEST 2019
Thread-7释放了permit,时候为Sun Sep 29 21:47:09 CEST 2019
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后拿到了返回效果。