public class CountDownLatchExample1 { public static void main(String[] args) throws Exception { ExecutorService exec = Executors1.newCachedThreadPool(); final CountDownLatch1 countDownLatch = new CountDownLatch1(3); for (int i = 0; i < 2; i++) { exec.execute(() -> { try { System.out.println("我我我我我我"); } catch (Exception e) { } finally { //state=0(不能向下减了,这个线程继续向下执行完,就不管CountDownLatch了,),减1之后!=0继续向下执行完。 //减1之后=0唤醒队列下一个节点。队列中只有main线程,实例化的线程不会去排队,只会执行完。 countDownLatch.countDown();// 为了保证必须减一,写在finally里面 } }); }//线程在这里已经执行完了, //state=0 main线程就向下执行,state!=0 main线程去排队。 countDownLatch.await(); // 减为0了才继续执行,这么多线程都减完了在一起走。 exec.shutdown(); // 线程次用完要关闭 } }
//共享锁(不是锁,只是说多线程可以同时执行),没有锁的概念,没有公平非公平之分, public class CountDownLatch1 { private static final class Sync extends AbstractQueuedSynchronizer1 { private static final long serialVersionUID = 4982264981922014374L; Sync(int count) { setState(count);//设置state } int getCount() { return getState(); } // 这个方法会经常调用,如果state=0,证明可以唤醒等待线程了 protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; } // 尝试去释放锁,调用CountDown()方法会调用此方法,将state-1 protected boolean tryReleaseShared(int releases) { for (;;) {// 死循环 int c = getState(); //一个是没减之前=0,一个是减1之后=0。没减之前=0就什么都不管了这个线程执行完算了。减1之后=0表示CountDownLatch变成了0就要唤醒主线程继续向下走。 if (c == 0) return false;//state=0不能向下减了,这个线程继续向下执行完,就不管CountDownLatch了, int nextc = c-1; if (compareAndSetState(c, nextc))//state减1失败继续死循环, return nextc == 0;//true:唤醒队列下一个节点(已经减完了,唤醒main线程),false:减1后继续向下执行完 } } } private final Sync sync; public CountDownLatch1(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); } public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1);//state=0 main线程就向下执行,state!=0 mian线程去排队。 } public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); } public void countDown() { //state=0(不能向下减了,这个线程继续向下执行完,就不管CountDownLatch了,),减1之后!=0继续向下执行完,不唤醒main线程。 //减1之后=0唤醒队列下一个节点。队列中只有main线程,实例化的线程不会去排队,只会执行完。 sync.releaseShared(1); } public long getCount() { return sync.getCount(); } public String toString() { return super.toString() + "[Count = " + sync.getCount() + "]"; } }