今天写一下这两个类的自己所得吧。
CyclicBarrier(循环屏障):
底层使用的ReetrantLock、LockSupport、AQS、CAS等技术。
使用的含义就是设置指定数量的屏障(通过构造函数赋值),通过await()方法让线程卡在屏障处,实现线程阻塞,阻挡当前线程后续的操作, 当多个线程调用await()方法的个数达到设定的屏障数时,所有的线程都会被唤醒。
线程的阻塞和唤醒使用的LockSupport的park和unpark方法,因为unpark方法可以指定线程进行唤醒。
之所以称之为循环屏障,是因为有个计数器记录调用await()方法的数量,计数器初始值为屏障数,调用一次await()方法就减1,调用次数达到预设的屏障数的时候,计数器会减到0,这个时候释放掉这批线程锁,同时将计数器重新设置为预设的屏障数。
因此,调用await()的线程数必须是预设屏障数的整数倍,才不会有线程在阻塞,否则会有线程在一直阻塞无法释放。
CountDownLatch(倒计数锁):
核心方法countDown()/await() 方法对。
底层使用的LockSupport、AQS、CAS等技术
await()方法会使用LockSupport.park()方法阻塞线程, 让线程等待
countDown()方法会使用LockSupport.uppark(thread)方法唤醒线程
CountDownLatch有两种使用场景:
1、模拟并发
设置CountDownLatch的初试状态值是1, 创建一堆的并发线程,使用await()等待线程的其他操作, 等待几秒后,主线程使用countDown()方法,唤醒所有线程,同时执行某操作。示例代码:
CountDownLatch cdl = new CountDownLatch(1);for(int i=0;i<50;i++){new Thread(new Runnable() {@Overridepublic void run() {try {cdl.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("并发执行====="+Thread.currentThread().getName());}},"我的线程【"+i+"】").start();}try {System.out.println("等待1秒开始并发执行");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}cdl.countDown();System.out.println("并发执行结束");
2、模拟某个线程等待其他线程完成之后进行操作
设置CountDownLatch的初试状态值是是需要执行操作的线程数,每个线程里面,执行完操作之后,调用countDown()方法, 然后在等待的线程中调用await()进行等待,所有线程调用了countDown()之后,await()方法会被唤醒。示例代码:
public static void main(String[] args) throws InterruptedException {CountDownLatch cdl = new CountDownLatch(1000);test2(cdl);}public static void test2(CountDownLatch cdl){long t1 = System.currentTimeMillis();Executor e = new ScheduledThreadPoolExecutor(10);for(int i=0;i<1000;i++){e.execute(new MyWork(cdl,i));}try {cdl.await();} catch (InterruptedException e1) {e1.printStackTrace();}long t2 = System.currentTimeMillis();System.out.println("耗时:" + (t2 - t1) + "ms============"+cdl.getCount());}static class MyWork implements Runnable {private CountDownLatch cd;private int i;public MyWork(CountDownLatch cd, int i) {this.cd = cd;this.i = i;}@Overridepublic void run() {doWork(i);try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}cd.countDown();}private void doWork(int i) {System.out.println("这是第" + i + "个循环,线程为" + Thread.currentThread().getName()+"==="+cd.getCount());}}