CountDownLatch能够理解为一个计数器在初始化时设置初始值,当一个线程须要等待某些操做先完成时,须要调用await()方法。这个方法让线程进入休眠状态直到等待的全部线程都执行完成。每调用一次countDown()方法内部计数器减1,当计数达到0时,则全部的等待着开始执行。 能够实现一个线程(也能够是多个线程)等待其余线程来唤醒,也能够实现一个线程通知多个线程的效果。java
(1)countDown():使CountDownLatch维护的内部计数器减1,每一个被等待的线程完成的时候调用。安全
(2)await():线程在执行到CountDownLatch的时候会将此线程置于休眠。并发
模拟裁判发出命令后,3个运动员以不一样的速度奔跑。等3个运动员都跑完后,裁判获得比赛结果。dom
import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * CountDownLatch demo :模拟裁判发出命令后,3个运动员以不一样的速度奔跑。等3个运动员都跑完后,裁判获得比赛结果 * * @author Smile */ public class CountdownLatchTest { public static void main(String[] args) throws InterruptedException { ExecutorService service = Executors.newCachedThreadPool(); // 建立一个“命令”计数器 final CountDownLatch cdOrder = new CountDownLatch(1); // 建立三个“回应”计数器 final CountDownLatch cdAnswer = new CountDownLatch(3); for (int i = 0; i < 3; i++) { Runnable runnable = new Runnable() { @Override public void run() { try { System.out.println("线程" + Thread.currentThread().getName() + "正在准备接收命令"); // 等待“命令”计数器为0 cdOrder.await(); System.out.println("线程" + Thread.currentThread().getName() + "已收命令"); Thread.sleep((long) (Math.random() * 10000)); System.out.println("线程" + Thread.currentThread().getName() + "处理结束!回应命令处理结果"); // “回应”计数器减1 cdAnswer.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } }; service.execute(runnable); } // 主线程发命令CountDownLatch cdOrder命令 Thread.sleep((long) (Math.random() * 10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将发布命令"); // “命令”计数器减1,“命令”计数器为0,开始唤醒cdOrder.await()的线程 cdOrder.countDown(); System.out.println("线程" + Thread.currentThread().getName() + "已发布命令,等待处理结果……"); // 等待“回应”计数器为0时,再继续执行 cdAnswer.await(); System.out.println("线程" + Thread.currentThread().getName() + "已收到所有结果结果。"); service.shutdown(); } }
运行结果:ide
CyclicBarrier是一个同步工具类,它容许一组线程互相等待,直到到达某个公共屏障点。工具
(1)await()方法:在调用await()方法后,CyclicBarrier将阻塞这个线程并将它置入休眠状态等待其它线程的到来。spa
(1)与CountDownLatch不一样的是该barrier在释放等待线程后能够重用,因此称它为循环(Cyclic)的屏障(Barrier)。线程
(2)CountDownLatch主要是实现了1个或N个线程须要等待其余线程完成某项操做以后才能继续往下执行操做,描述的是1个线程或N个线程等待其余线程的关系。CyclicBarrier主要是实现了多个线程之间相互等待,直到全部的线程都知足了条件以后各自才能继续执行后续的操做,描述的多个线程内部相互等待的关系。code
模拟线程一、线程二、线程3以不一样时间到达集合点1后,再一块儿以不一样的速度到达集合点2,等全部线程都到达集合点2后,再一块儿出发到集合点3。对象
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * CyclicBarrier * Demo:模拟线程一、线程二、线程3以不一样时间到达集合点1后,再一块儿以不一样的速度到达集合点2,等全部线程都到达集合点2后,再一块儿出发到集合点3 * * @author Smile */ public class CyclicBarrierTest { /** * @param args */ public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); // 设置屏障,此屏障须要等待3个线程 final CyclicBarrier cb = new CyclicBarrier(3); for (int i = 0; i < 3; i++) { Runnable runable = new Runnable() { @Override public void run() { try { Thread.sleep((long) (Math.random() * 10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点1, 当前已有" + (cb.getNumberWaiting() + 1) + "个并发" + ((2 == cb.getNumberWaiting()) ? "。线程已经所有到达集合点1,继续往下走!" : "")); cb.await(); // 设置第一次屏障,需等3个线程所有执行到此时,才继续往下 Thread.sleep((long) (Math.random() * 10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点2, 当前已有" + (cb.getNumberWaiting() + 1) + "个并发" + ((2 == cb.getNumberWaiting()) ? "。线程已经所有到达集合点2,继续往下走!" : "")); cb.await(); // 设置第二次屏障,需等3个线程所有执行到此时,才继续往下 Thread.sleep((long) (Math.random() * 10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点3, 当前已有" + (cb.getNumberWaiting() + 1) + "个并发" + ((2 == cb.getNumberWaiting()) ? "。线程已经所有到达集合点3,完毕!" : "")); cb.await(); // 设置第三次屏障,需等3个线程所有执行到此时,才继续往下 } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }; service.execute(runable); } service.shutdown(); } }
运行结果:
用于实现两我的之间的数据交换,每一个人在完成必定的事务后想与对方交互数据,第一个先拿出数据的人将一直等待第二我的拿着数据到来时,才彼此交换数据。
public V exchange(V x):等待另外一个线程到达交换点(若是当前线程没有被中断),而后将已知的对象传给它,返回接收的对象。
模拟两个线程交换数据:当线程A调用Exchange对象的exchange()方法后,他会陷入阻塞状态,直到线程B也调用了exchange()方法,而后以线程安全的方式交换数据,以后线程A和B继续运行。
import java.util.concurrent.Exchanger; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Exchanger Demo:两个线程之间的信息交换 * 用于实现两我的之间的数据交换,每一个人在完成必定的事务后想与对方交互数据,第一个先拿出数据的人将一直等待第二我的拿着数据到来时,才彼此交换数据 * * @author xiao * */ public class ExchangerTest { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); final Exchanger exchanger = new Exchanger(); service.execute(new Runnable() { @Override public void run() { try { String data1 = "XMSSS"; System.out.println("线程" + Thread.currentThread().getName() + "正在把数据 " + data1 + "交换出去"); Thread.sleep((long) (Math.random() * 10000)); String data2 = (String) exchanger.exchange(data1); System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为 " + data2); } catch (InterruptedException e) { e.printStackTrace(); } } }); service.execute(new Runnable() { @Override public void run() { try { String data1 = "GRSXX"; System.out.println("线程" + Thread.currentThread().getName() + "正在把数据 " + data1 + "交换出去"); Thread.sleep((long) (Math.random() * 10000)); String data2 = (String) exchanger.exchange(data1); System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为 " + data2); } catch (InterruptedException e) { e.printStackTrace(); } } }); } }
运行效果: