今天写一下这两个类的自己所得吧。
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() {
@Override
public 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;
}
@Override
public 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());
}
}