天天看點

并發-同步工具類CountDownLatch

CountDownLatch是一個同步工具,它允許一個或者多個線程一直等待,直到其他線程的操作執行完成後在執行。

CountDownLatch是通過一個計數器來實作的,計數器的初始值為線程的數量。每當一個線程完成了自己的任務後,計數器的值就會減1。當計數器的值達到0時,它表示所有的線程已經完成了任務,然後在閉鎖上等待的線程就可以恢複執行任務。

并發-同步工具類CountDownLatch

1. 源碼分析:  源碼位于rt.java 中的java.util.concurrent包中。

中文解釋: 主線程在等待所有其他的子線程執行完成後在往下執行

2、構造函數:CountDownLatch(int count)//初始化count數目的同步計數器,隻有當同步計數器為0,主線程才會向下執行

主要方法:void await()//目前線程等待計數器為0 

boolean await(long timeout, TimeUnit unit)//與上面的方法不同,它加了一個時間限制。

void countDown()//計數器減1

long getCount()//擷取計數器的值

3、它的内部有一個輔助的内部類: sync

實作如下:

/**
     * Synchronization control For CountDownLatch.
     * Uses AQS state to represent count.
     */
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = ;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        protected int tryAcquireShared(int acquires) {
            return (getState() == ) ?  : -;
        }

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == )
                    return false;
                int nextc = c-;
                if (compareAndSetState(c, nextc))
                    return nextc == ;
            }
        }
    }
           

4.await()方法的實作

public void await() throws InterruptedException {
   sync.acquireSharedInterruptibly();
}
public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        //調用3中的tryAcquireShared()方法
        if (tryAcquireShared(arg) < )
            doAcquireSharedInterruptibly(arg);//加入到等待隊列中
    }
           

5.countDown()方法的實作

public void countDown() {
        sync.releaseShared();
}
public final boolean releaseShared(int arg) {
//調用3中的tryReleaseShared()方法
        if (tryReleaseShared(arg)) {
        //解鎖
            doReleaseShared();
            return true;
        }
        return false;
}
           

應用場景:

  比如主任務是一個比較複雜的運算,為了節約時間,我們可以拆分為多個子任務,多線程同時執行,最終統一彙總任務。

  其實生活也有類似的場景,比如馬拉松賽跑,我們不可能按順序依次跑步,這樣得跑到猴年馬月。一般來說都是大家聽到發号指令一起跑,最終比賽結束,統一彙總成績。

 代碼案列:

 下面看一個例子大家就清楚CountDownLatch的用法了:

/**
 * CountDownLatch,一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待
 * 構造方法參數指定了計數的次數
 * countDown方法,目前線程結束執行後調用,計數減一 
 * awaint方法,調用此方法會一直阻塞目前線程,直到計時器的值為0
 * 建立時間    2017年8月15日
 *
 */
public class CountDownLatchDemo {
    final static SimpleDateFormat sdf = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");
    
    final static String startTime = sdf.format(new Date());

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch();// 兩個賽跑者
        Runer runer1 = new Runer("劉翔", , latch);
        Runer runer2 = new Runer("羅伯斯", , latch);
        runer1.start();//劉翔   開始跑步
        runer2.start();//羅伯斯 開始跑步
        latch.await();// 等待所有人賽跑結束
        System.out.println("all runer done at " + sdf.format(new Date()));
    }

    static class Runer extends Thread {
        String runerName;
        int runTime;
        CountDownLatch latch;

        public Runer(String runerName, int runTime, CountDownLatch latch) {
            this.runerName = runerName;
            this.runTime = runTime;
            this.latch = latch;
        }

        public void run() {
            System.out.println("Runer " + runerName + " do run begin at "
                    + startTime);
            doRun();//跑步
            System.out.println("Runer " + runerName + " do run complete at "
                    + sdf.format(new Date()));
            latch.countDown();// 終點結束,計數器減一

        }

        private void doRun() {
            try {
                Thread.sleep(runTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
           

繼續閱讀