openstack 本地yum源搭建
阿新 • • 發佈:2020-11-22
一 使用場景
在網上找了個例子,這個例子很好地說明了CountDownLatch 的用法,概括地說就是主執行緒等待子執行緒執行完了,主執行緒接著執行
public class CountDownLatchTest { public static void main(String[] args) { final CountDownLatch latch = new CountDownLatch(2); System.out.println("主執行緒開始執行…… ……"); //第一個子執行緒執行 ExecutorService es1 = Executors.newSingleThreadExecutor(); es1.execute(new Runnable() { @Override public void run() { try { Thread.sleep(3000); System.out.println("子執行緒:"+Thread.currentThread().getName()+"執行"); } catch (InterruptedException e) { e.printStackTrace(); } latch.countDown(); } }); es1.shutdown();//第二個子執行緒執行 ExecutorService es2 = Executors.newSingleThreadExecutor(); es2.execute(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("子執行緒:"+Thread.currentThread().getName()+"執行"); latch.countDown(); } }); es2.shutdown(); System.out.println("等待兩個執行緒執行完畢…… ……"); try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("兩個子執行緒都執行完畢,繼續執行主執行緒"); } }
二 程式碼概況
CountDownLatch的功能都是通過內部實現AQS來實現的
private static final class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 4982264981922014374L; Sync(int count) { setState(count); } int getCount() { return getState(); } protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; } protected boolean tryReleaseShared(int releases) { // Decrement count; signal when transition to zero for (;;) { int c = getState(); if (c == 0) return false; int nextc = c-1; if (compareAndSetState(c, nextc)) return nextc == 0; } } } private final Sync sync;
CountDownLatch的構造方法如下
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
使用者傳進去的count就賦值給AQS的state
三 await原始碼分析
public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); }
之前分析過共享鎖的程式碼,共享鎖的主要邏輯還是要看使用者實現的tryAcquireShared
protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; }
如果state不是0的話,返回-1,這樣主執行緒就會進到佇列中排隊,並把自己阻塞起來,只能等待其他執行緒的喚醒
四 CountDown原始碼分析
每次呼叫countDown() 固定是釋放一個共享資源
public void countDown() { sync.releaseShared(1); }
protected boolean tryReleaseShared(int releases) { // Decrement count; signal when transition to zero for (;;) { int c = getState(); if (c == 0)//如果已經是0,那就沒法釋放了,返回false,這樣就不會執行unpark方法 return false; int nextc = c-1; if (compareAndSetState(c, nextc))//減一成功後比較state是不是0,如果返回true return nextc == 0; } }
如果state == 0,那麼tryReleaseShared返回true,這樣就會執行unpark的邏輯,這樣主執行緒被喚醒,程式碼就可以繼續執行了
五 總結
CountDownLatch的原始碼不多,邏輯也不復雜,但是可以很好的看看如果通過繼承AQS實現自己的邏輯。