CountDownLatch 和 CyclicBarrier
2016-07-14 11:25
471 查看
闭锁 CountDownLatch 和 循环栅栏 CyclicBarrier 都是同步工具类。
所有的同步工具类包含一些特定的结构化属性: 它们封装了一些状态,这些状态将决定执行同步工具类的线程是继续执行还是等待,此外还提供了一些方法对状态进行操作,以及另一些方法用于高效地等待同步工具类进入到预期状态。
一、闭锁 CountDownLatch
CountDownLatch 是一种灵活的闭锁实现,它可以使一个或者多个线程等待一组事件发生;
闭锁状态包括一个计数器,该计数器被初始化为一个正数,表示需要等待的事件数量。countDown 方法递减计数器,表示有一个事件已经发生了,而 await 方法等待计数器达到零,这表示所有需要等待的事件都已经发生。如果计数器的值非零,那么
await 会一直阻塞直到计数器为零,或者等待中的线程中断,或者等待超时;
CountDownlatch 允许线程等待直到计数器减为 0;
使用场合: 当一个或多个线程需要等待直到指定数目的事件发生。
例子:
运行结果:
二、樟栅 CyclicBarrier
CyclicBarrier 类实现了一个集结点(rendezvous) 称为樟栅(barrier)。 考虑大量线程运算在一次计算的不同部分的情形。当所有部分都
准备好时,需要把结果组合在一起。当一个线程完成了它的那一部分后,让它运行到樟栅处。一旦所有的线程都到达了这个樟栅,樟栅就撤销,
线程就可以继续运行了。
如果任何一个在樟栅上等待的线程离开了樟栅,那么樟栅就被破坏了(线程可能离开是因为它调用 await 时设置了超时,或者因为它被中断
了)。在这种情况下,所有其他线程的 await 方法抛出 BrokenBarrierExecption 异常。那些已经在等待的线程立即终止 await 的调用。
可以提供一个可选的樟栅动作(barrier action), 当所有线程到达樟栅的时候就会执行这一动作。
Runnable barrierAction = ...;
CyclicBarrier barrier = new CyclicBarrier(nThreads, barrierAction);
樟栅被称为是循环的(cyclic),因为可以在所有等待线程被释放后被重用。这点,有别于 CountDownLatch,CountDownLatch 只能被使用一
次。
例子:
运行结果:
三、CountDownLatch 和 CyclicBarrier 的区别
1、樟栅与闭锁的关键区别在于,所有线程必须同时达到樟栅位置,才能继续执行。闭锁用于等待事件,而樟栅用于等待其他线
程;
2、CountDownLatch 的作用是允许1个或者 N 个线程等待其他线程完成执行,而 CyclicBarrier 则是允许 N 个线程相互等待;
3、CountDownLatch 的计数器无法被重置,CyclicBarrier 的计数器可以被重置后使用,因此,它被称为是循环的 barrier.
四、说明:
1、SharedPreferences 源码中 apply 方法的 awaitCommit 任务中就使用了 CountDownLatch;
2、这里是《Java 核心技术卷I》第14章 P688, 《Java 并发编程》第五章 P83, 《Android 开发进阶 从小工到专家》 第3章 P94
的内容的综合。
所有的同步工具类包含一些特定的结构化属性: 它们封装了一些状态,这些状态将决定执行同步工具类的线程是继续执行还是等待,此外还提供了一些方法对状态进行操作,以及另一些方法用于高效地等待同步工具类进入到预期状态。
一、闭锁 CountDownLatch
CountDownLatch 是一种灵活的闭锁实现,它可以使一个或者多个线程等待一组事件发生;
闭锁状态包括一个计数器,该计数器被初始化为一个正数,表示需要等待的事件数量。countDown 方法递减计数器,表示有一个事件已经发生了,而 await 方法等待计数器达到零,这表示所有需要等待的事件都已经发生。如果计数器的值非零,那么
await 会一直阻塞直到计数器为零,或者等待中的线程中断,或者等待超时;
CountDownlatch 允许线程等待直到计数器减为 0;
使用场合: 当一个或多个线程需要等待直到指定数目的事件发生。
例子:
public class CountDownLatchTest { private static int LATCH_SIZE = 5; public static void main(String[] args) { try { CountDownLatch latch = new CountDownLatch(LATCH_SIZE); for(int i = 0; i < LATCH_SIZE; i++){ new WorkerThread(latch).start(); } System.out.println("主线程等待."); latch.await(); System.out.println("主线程继续执行"); } catch (InterruptedException e) { e.printStackTrace(); } } static class WorkerThread extends Thread{ CountDownLatch mLatch; public WorkerThread(CountDownLatch latch){ mLatch = latch; } @Override public void run() { super.run(); try { Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + " 执行操作."); // 将 CountDownLatch 的数量减 1 mLatch.countDown(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
运行结果:
二、樟栅 CyclicBarrier
CyclicBarrier 类实现了一个集结点(rendezvous) 称为樟栅(barrier)。 考虑大量线程运算在一次计算的不同部分的情形。当所有部分都
准备好时,需要把结果组合在一起。当一个线程完成了它的那一部分后,让它运行到樟栅处。一旦所有的线程都到达了这个樟栅,樟栅就撤销,
线程就可以继续运行了。
如果任何一个在樟栅上等待的线程离开了樟栅,那么樟栅就被破坏了(线程可能离开是因为它调用 await 时设置了超时,或者因为它被中断
了)。在这种情况下,所有其他线程的 await 方法抛出 BrokenBarrierExecption 异常。那些已经在等待的线程立即终止 await 的调用。
可以提供一个可选的樟栅动作(barrier action), 当所有线程到达樟栅的时候就会执行这一动作。
Runnable barrierAction = ...;
CyclicBarrier barrier = new CyclicBarrier(nThreads, barrierAction);
樟栅被称为是循环的(cyclic),因为可以在所有等待线程被释放后被重用。这点,有别于 CountDownLatch,CountDownLatch 只能被使用一
次。
例子:
public class CyclicBarrierTest { private static final int SIZE = 5; private static CyclicBarrier mCyclicBarrier; public static void main(String[] args) { mCyclicBarrier = new CyclicBarrier(SIZE, new Runnable() { @Override public void run() { // 当所有线程到达 barrier(樟栅) 的时候就会执行 barrier action. System.out.println("---> 满足条件,执行特定操作"); } }); // 创建 5 个任务 for(int i = 0; i < SIZE; i++){ new WorkerThread().start(); } } static class WorkerThread extends Thread{ @Override public void run() { super.run(); try { System.out.println(Thread.currentThread().getName() + " 等待 CyclicBarrier."); // 将 mCyclicBarrier 的参与者数量加 1 mCyclicBarrier.await(); // mCyclicBarrier 的参与者数量等于 5 时,才继续往后执行 System.out.println(Thread.currentThread().getName() + " 继续执行."); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BrokenBarrierException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
运行结果:
三、CountDownLatch 和 CyclicBarrier 的区别
1、樟栅与闭锁的关键区别在于,所有线程必须同时达到樟栅位置,才能继续执行。闭锁用于等待事件,而樟栅用于等待其他线
程;
2、CountDownLatch 的作用是允许1个或者 N 个线程等待其他线程完成执行,而 CyclicBarrier 则是允许 N 个线程相互等待;
3、CountDownLatch 的计数器无法被重置,CyclicBarrier 的计数器可以被重置后使用,因此,它被称为是循环的 barrier.
四、说明:
1、SharedPreferences 源码中 apply 方法的 awaitCommit 任务中就使用了 CountDownLatch;
2、这里是《Java 核心技术卷I》第14章 P688, 《Java 并发编程》第五章 P83, 《Android 开发进阶 从小工到专家》 第3章 P94
的内容的综合。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories