成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java 多線程基礎(chǔ) - CyclicBarrier

freecode / 665人閱讀

摘要:序包里有幾個能幫助人們管理相互合作的線程集的類,為多線程常見的應(yīng)用場景預(yù)置了抽象好的類庫。如果沒報錯就更新屏障狀態(tài)并喚醒所有線程繼續(xù)執(zhí)行。如果還有未到達(dá)的線程,就進(jìn)入一個死循環(huán),直到超時線程中斷屏障失效全部完成等情況下退出。

我的博客   轉(zhuǎn)載請注明原創(chuàng)出處。

java.util.concurrent包里有幾個能幫助人們管理相互合作的線程集的類,為多線程常見的應(yīng)用場景預(yù)置了抽象好的類庫。在遇到這些應(yīng)用場景時應(yīng)該直接重用合適的庫類而不要試圖提供手工的鎖與條件的集合。

同步屏障 CyclicBarrier

官方定義上文已經(jīng)給出,人話版是等待特定數(shù)量的線程都到達(dá)同步屏障后各線程才繼續(xù)執(zhí)行。

同步屏障有兩個構(gòu)造函數(shù),第一個構(gòu)造函數(shù)只需要指定需要等待的線程數(shù)量,第二構(gòu)造函數(shù)多了一個在特定數(shù)量的線程都到達(dá)同步屏障時優(yōu)先執(zhí)行的Runnable

例子:

public class CyclicBarrierTest {

    // 等待4個線程到達(dá)同步屏障,全部到達(dá)后優(yōu)先執(zhí)行一個 Runnable
    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(4,
    () -> System.out.println("全部到達(dá)同步屏障" + LocalDateTime.now()));

    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
        Runnable runnable = () -> {
            System.out.println("到達(dá)同步屏障" + LocalDateTime.now());
            try {
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println("繼續(xù)執(zhí)行");
        };
        List list = Arrays.asList(runnable, runnable, runnable);
        list.forEach(runnable1 -> new Thread(runnable1).start());
        Thread.sleep(1000);
        System.out.println("最后一個線程到達(dá)同步屏障");
        cyclicBarrier.await();
    }

}

輸出:

到達(dá)同步屏障2018-08-12T14:33:16.769
到達(dá)同步屏障2018-08-12T14:33:16.769
到達(dá)同步屏障2018-08-12T14:33:16.769
最后一個線程到達(dá)同步屏障
全部到達(dá)同步屏障2018-08-12T14:33:17.746
繼續(xù)執(zhí)行
繼續(xù)執(zhí)行
繼續(xù)執(zhí)行

Process finished with exit code 0

同步屏障的應(yīng)用場景是那種多線程執(zhí)行任務(wù),在全部任務(wù)執(zhí)行完成后需要進(jìn)行一些操作的場景。比如對每個用戶進(jìn)行充值統(tǒng)計,最后匯總返回。

CyclicBarrier的方法如上,分別是

getParties()  返回需要到達(dá)同步屏障的線程數(shù)量
await() 等待所有線程到達(dá)
await(long, TimeUnit) 帶時間限制的await()
isBroken() 判斷阻塞的線程是否被中斷
reset() 重置計數(shù)器
getNumberWaiting() 當(dāng)前被阻塞的線程數(shù)量,該方法主要用于調(diào)試和斷言
源碼分析

那么CyclicBarrier是怎么實現(xiàn)這個效果的呢?我們從最常用的await()方法入手。

可以看到await()方法主要是調(diào)用了CyclicBarrier私有的dowait()方法

如注釋所言,dowait()方法就是實現(xiàn)功能的主要方法了。

首先拿到可重入的鎖


然后通過內(nèi)部類Generation判斷阻塞的線程是否被中斷或該屏障已經(jīng)失效。

如果線程沒有被中斷,那么就獲取還沒有到達(dá)的線程數(shù)量并減一。如果已經(jīng)沒有需要等待的線程了,就判斷是否有需要執(zhí)行的Runnable。如果沒報錯就更新屏障狀態(tài)并喚醒所有線程繼續(xù)執(zhí)行。Runnable執(zhí)行報錯的話執(zhí)行breakBarrier()方法。

如果還有未到達(dá)的線程,就進(jìn)入一個死循環(huán),直到超時、線程中斷、屏障失效、全部完成等情況下退出。

完整的代碼:

/**
     * Each use of the barrier is represented as a generation instance.
     * The generation changes whenever the barrier is tripped, or
     * is reset. There can be many generations associated with threads
     * using the barrier - due to the non-deterministic way the lock
     * may be allocated to waiting threads - but only one of these
     * can be active at a time (the one to which {@code count} applies)
     * and all the rest are either broken or tripped.
     * There need not be an active generation if there has been a break
     * but no subsequent reset.
     */
    private static class Generation {
        boolean broken = false;
    }

    /** The lock for guarding barrier entry */
    private final ReentrantLock lock = new ReentrantLock();
    /** Condition to wait on until tripped */
    private final Condition trip = lock.newCondition();
    /** The number of parties */
    private final int parties;
    /* The command to run when tripped */
    private final Runnable barrierCommand;
    /** The current generation */
    private Generation generation = new Generation();

    /**
     * Number of parties still waiting. Counts down from parties to 0
     * on each generation.  It is reset to parties on each new
     * generation or when broken.
     */
    private int count;

    /**
     * Updates state on barrier trip and wakes up everyone.
     * Called only while holding lock.
     */
    private void nextGeneration() {
        // signal completion of last generation
        trip.signalAll();
        // set up next generation
        count = parties;
        generation = new Generation();
    }

    /**
     * Sets current barrier generation as broken and wakes up everyone.
     * Called only while holding lock.
     */
    private void breakBarrier() {
        generation.broken = true;
        count = parties;
        trip.signalAll();
    }

    /**
     * Main barrier code, covering the various policies.
     */
    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            final Generation g = generation;

            if (g.broken)
                throw new BrokenBarrierException();

            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

            int index = --count;
            if (index == 0) {  // tripped
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        breakBarrier();
                }
            }

            // loop until tripped, broken, interrupted, or timed out
            for (;;) {
                try {
                    if (!timed)
                        trip.await();
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        // We"re about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        Thread.currentThread().interrupt();
                    }
                }

                if (g.broken)
                    throw new BrokenBarrierException();

                if (g != generation)
                    return index;

                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/71766.html

相關(guān)文章

  • Java并發(fā)線程 - 并發(fā)工具類JUC

    摘要:將屏障重置為其初始狀態(tài)。注意,在由于其他原因造成損壞之后,實行重置可能會變得很復(fù)雜此時需要使用其他方式重新同步線程,并選擇其中一個線程來執(zhí)行重置。 安全共享對象策略 1.線程限制 : 一個被線程限制的對象,由線程獨占,并且只能被占有它的線程修改2.共享只讀 : 一個共享只讀的對象,在沒有額外同步的情況下,可以被多個線程并發(fā)訪問,但是任何線程都不能修改它3.線程安全對象 : 一個線程安全...

    wuyumin 評論0 收藏0
  • Java線程進(jìn)階(十九)—— J.U.C之synchronizer框架:CyclicBarrier

    摘要:當(dāng)?shù)竭_(dá)柵欄后,由于沒有滿足總數(shù)的要求,所以會一直等待,當(dāng)線程到達(dá)后,柵欄才會放行。任務(wù)其實就是當(dāng)最后一個線程到達(dá)柵欄時,后續(xù)立即要執(zhí)行的任務(wù)。 showImg(https://segmentfault.com/img/remote/1460000016010958); 本文首發(fā)于一世流云專欄:https://segmentfault.com/blog... 一、CyclicBarri...

    tulayang 評論0 收藏0
  • java線程系列:通過對戰(zhàn)游戲?qū)W習(xí)CyclicBarrier

    摘要:當(dāng)位玩家角色都選擇完畢后,開始進(jìn)入游戲。進(jìn)入游戲時需要加載相關(guān)的數(shù)據(jù),待全部玩家都加載完畢后正式開始游戲。 showImg(https://segmentfault.com/img/remote/1460000016414941?w=640&h=338); CyclicBarrier是java.util.concurrent包下面的一個工具類,字面意思是可循環(huán)使用(Cyclic)的屏障...

    wangbjun 評論0 收藏0
  • Java線程打輔助的三個小伙子

    摘要:前言之前學(xué)多線程的時候沒有學(xué)習(xí)線程的同步工具類輔助類。而其它線程完成自己的操作后,調(diào)用使計數(shù)器減。信號量控制一組線程同時執(zhí)行。 前言 之前學(xué)多線程的時候沒有學(xué)習(xí)線程的同步工具類(輔助類)。ps:當(dāng)時覺得暫時用不上,認(rèn)為是挺高深的知識點就沒去管了.. 在前幾天,朋友發(fā)了一篇比較好的Semaphore文章過來,然后在瀏覽博客的時候又發(fā)現(xiàn)面試還會考,那還是挺重要的知識點。于是花了點時間去了解...

    pingink 評論0 收藏0
  • Java 線程同步組件 CountDownLatch 與 CyclicBarrier 原理分析

    摘要:在創(chuàng)建對象時,需要轉(zhuǎn)入一個值,用于初始化的成員變量,該成員變量表示屏障攔截的線程數(shù)。當(dāng)?shù)竭_(dá)屏障的線程數(shù)小于時,這些線程都會被阻塞住。當(dāng)所有線程到達(dá)屏障后,將會被更新,表示進(jìn)入新一輪的運行輪次中。 1.簡介 在分析完AbstractQueuedSynchronizer(以下簡稱 AQS)和ReentrantLock的原理后,本文將分析 java.util.concurrent 包下的兩個...

    Anonymous1 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<