1.CyclicBarrier
表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面
package org.lkl.thead.foo; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面 */ public class CyclicBarrierFoo { public static void main(String[] args) { ExecutorService threadPool = Executors.newCachedThreadPool() ; final CyclicBarrier cyclicBarrier = new CyclicBarrier(3) ; //表示有3个线程需要彼此等待 都执行到 cyclicBarrier.await() ;以后才继续执行 for(int i=1 ;i<=3 ;i++){ Runnable r = new Runnable() { @Override public void run() { try { Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点1,当前已有" + (cyclicBarrier.getNumberWaiting()+1) + "个已经到达," + (cyclicBarrier.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候")); cyclicBarrier.await() ; //类似于集合点 Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点2,当前已有" + (cyclicBarrier.getNumberWaiting()+1) + "个已经到达," + (cyclicBarrier.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候")); cyclicBarrier.await() ; //类似于集合点 Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点3,当前已有" + (cyclicBarrier.getNumberWaiting()+1) + "个已经到达," + (cyclicBarrier.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候")); cyclicBarrier.await() ; //类似于集合点 } catch (Exception e) { e.printStackTrace(); } } }; threadPool.execute(r) ; } } }
允许结果如下:
线程pool-1-thread-3即将到达集合地点1,当前已有1个已经到达,正在等候 线程pool-1-thread-1即将到达集合地点1,当前已有2个已经到达,正在等候 线程pool-1-thread-2即将到达集合地点1,当前已有3个已经到达,都到齐了,继续走啊 线程pool-1-thread-3即将到达集合地点2,当前已有1个已经到达,正在等候 线程pool-1-thread-1即将到达集合地点2,当前已有2个已经到达,正在等候 线程pool-1-thread-2即将到达集合地点2,当前已有3个已经到达,都到齐了,继续走啊 线程pool-1-thread-2即将到达集合地点3,当前已有1个已经到达,正在等候 线程pool-1-thread-1即将到达集合地点3,当前已有2个已经到达,正在等候 线程pool-1-thread-3即将到达集合地点3,当前已有3个已经到达,都到齐了,继续走啊
2. CountdownLatchFoo
犹如倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减1,当计数到达0时,则所有等待者或单个等待者开始执行
可以实现一个人(也可以是多个人)等待其他所有人都来通知他,这犹如一个计划需要多个领导都签字后才能继续向下实施。还可以实现一个人通知多个人的效果,类似裁判一声口令,运动员同时开始奔跑
package org.lkl.thead.foo; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CountdownLatchFoo { /** * 实现代码: * 主线程发布命令 然后开启三个线程在等待主线程发布的命令 , * 当子线程接收命令以后 传递一个回调的命令给主线程 然后主线程接收回调命令 */ public static void main(String[] args) { final CountDownLatch orderLatch = new CountDownLatch(1) ; //表示从1 开始倒计时 final CountDownLatch answerLatch = new CountDownLatch(3) ; //表示从3开始倒计时 ExecutorService threadPool = Executors.newCachedThreadPool() ; for(int i=1 ;i<=3 ;i++){ Runnable runnable = new Runnable() { @Override public void run() { System.out.println("线程"+Thread.currentThread().getName()+"准备接收数据."); try { orderLatch.await() ; //表示等待主线程发布命令,没有接收到命令就会一致等待下去 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程"+Thread.currentThread().getName()+" 接收到命令 "); //只有接收到命令 程序才会从await方法中执行下来 //给主线程回调命令 System.out.println("线程"+Thread.currentThread().getName()+" 准备向主线程回调. "); try { Thread.sleep((long)(Math.random()*10000)); } catch (InterruptedException e) { e.printStackTrace(); } answerLatch.countDown() ; //表示发布命令 从3开始倒计时 前期主线程会被answerLatch.await() 方法拦截下来 等待回调 System.out.println("线程"+Thread.currentThread().getName()+" 已经向主线程回调. "); } }; threadPool.execute(runnable) ; } //主线程 try { Thread.sleep((long)(Math.random()*10000)); System.out.println("主线程"+Thread.currentThread().getName()+"准备向三个子线程发送命令."); orderLatch.countDown() ; //向三个子线程发送命令 System.out.println("主线程"+Thread.currentThread().getName()+"已经向三个子线程发送命令."); System.out.println("主线程"+Thread.currentThread().getName()+"等待三个子线程的回调."); answerLatch.await() ; System.out.println("主线程"+Thread.currentThread().getName()+"已经收到三个子线程的回调."); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
线程pool-1-thread-1准备接收数据. 线程pool-1-thread-2准备接收数据. 线程pool-1-thread-3准备接收数据. 主线程main准备向三个子线程发送命令. 线程pool-1-thread-2 接收到命令 线程pool-1-thread-2 准备向主线程回调. 主线程main已经向三个子线程发送命令. 主线程main等待三个子线程的回调. 线程pool-1-thread-3 接收到命令 线程pool-1-thread-3 准备向主线程回调. 线程pool-1-thread-1 接收到命令 线程pool-1-thread-1 准备向主线程回调. 线程pool-1-thread-1 已经向主线程回调. 线程pool-1-thread-2 已经向主线程回调. 线程pool-1-thread-3 已经向主线程回调. 主线程main已经收到三个子线程的回调.
3. Exchanger
用于实现两个人之间的数据交换,每个人在完成一定的事务后想与对方交换数据,第一个先拿出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据
package org.lkl.thead.foo; import java.util.concurrent.Exchanger; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExchangerFoo { public static void main(String[] args) { ExecutorService threadPool = Executors.newCachedThreadPool() ; final Exchanger<String> change = new Exchanger<String>() ; threadPool.execute(new Runnable() { @Override public void run() { try { String myData = "zhangsan" ; System.out.println("线程" + Thread.currentThread().getName() + "正在把数据" + myData +"换出去"); String mychange = change.exchange(myData) ; Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "换回来的数据为" + mychange); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }) ; threadPool.execute(new Runnable() { @Override public void run() { try { String myData = "lisi" ; System.out.println("线程" + Thread.currentThread().getName() + "正在把数据" + myData +"换出去"); String mychange = change.exchange(myData) ; Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "换回来的数据为" + mychange); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }) ; } }
运行结果:
线程pool-1-thread-2正在把数据lisi换出去 线程pool-1-thread-1正在把数据zhangsan换出去 线程pool-1-thread-2换回来的数据为zhangsan 线程pool-1-thread-1换回来的数据为lisi