用法理解
呃, 这个类的作用就是 让线程 等待别的线程走完之后自己在执行。比如有个需求 线程A、B要等待线程C、D、E执行完,才能继续往下走。
public class TestCountDownLatch {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(3);
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + " 等待");
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + " 等待");
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "B").start();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + "开始执行");
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + "执行完毕");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "C").start();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + "开始执行");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + "执行完毕");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "D").start();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + "开始执行");
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName() + "执行完毕");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "E").start();
}
}
A 等待
B 等待
C开始执行
D开始执行
E开始执行
C执行完毕
D执行完毕
E执行完毕
A执行完毕
B执行完毕
Process finished with exit code 0
呃, 所以锁CountDownLatch还是挺好用的。
使用Synchronized实现CounDownLatch
设计思路:
使用一个变量记录倒计数
countDown 使得倒计数减少1,如果为0就notifayALL
await 如果倒计数不为0就wait
public class SynchronizedCountDownLatch {
private int count = 0;
private Object moniter = new Object();
public SynchronizedCountDownLatch(int count) {
this.count = count;
}
public void countDown(){
synchronized (moniter){
count--;
if (count == 0){
moniter.notifyAll();
}
}
}
public void await(){
synchronized (moniter){
while (count != 0){
try {
moniter.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
使用AQS实现CounDownLatch
public class AqsCountDown {
private Sync sync;
public AqsCountDown(int count) {
sync = new Sync(count);
}
private static class Sync extends MyAbstractQueueSynchronizer {
public Sync(int count) {
setState(count);
}
@Override
protected int tryAquireShared(int premits) {
int state = getState();
if (state > 0) {
return -1;
}
return 1;
}
@Override
protected boolean tryReleaseShared(int i) {
int state = getState();
int update = state - i;
if (update < 0) {
throw new IllegalMonitorStateException();
}
while (true) {
if (compareAndSetState(state, update)) {
break;
}
state = getState();
update = state - i;
}
if (getState() == 0) {
return true;
} else {
return false;
}
}
}
public void countDown() {
sync.releaseShared();
}
public void await() {
sync.acquireShared(1);
}
}
总结
呃, CountDownLatch 思想挺好的。 需要注意区分ReentranctLock、Semaphore、CountDownLatch 三者 使用AQS state变量的含义
呃:
ReenTrantLock: state代表一把锁。
Semaphore: state 代表 n把锁。
CountDownLatch: state代表n个标记数 为1把锁