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

資訊專欄INFORMATION COLUMN

AbstractQueuedSynchronizer理解之三(Semaphore)

馬忠志 / 2544人閱讀

摘要:信號(hào)可以理解為一種許可,拿到許可的線程才可以繼續(xù)執(zhí)行。的計(jì)數(shù)器其實(shí)記錄的就是許可的數(shù)量,當(dāng)許可數(shù)量為時(shí),方法就會(huì)阻塞。

本文接著分析Semaphore的實(shí)現(xiàn)原理

Semaphore是什么

Semaphore是一個(gè)計(jì)數(shù)信號(hào)量。Semaphore(信號(hào))可以理解為一種許可,拿到許可的線程才可以繼續(xù)執(zhí)行。Semaphore的計(jì)數(shù)器其實(shí)記錄的就是許可的數(shù)量,當(dāng)許可數(shù)量為0時(shí),acquire方法就會(huì)阻塞。這個(gè)系統(tǒng)和停車位系統(tǒng)非常相似,當(dāng)停車場還有空位的時(shí)候,任何新來的車輛都可以進(jìn),當(dāng)停車場滿的時(shí)候,新來的車輛必須要等到有空車位產(chǎn)生的時(shí)候才可以開進(jìn)停車場。這里的停車位就相當(dāng)于Semaphore的許可數(shù)量。

Semaphore的使用方法
public static void main(String[] args) throws InterruptedException{
    Semaphore semaphore = new Semaphore(3);

    for (int i = 1; i <= 5; i++) {
        final int threadNum = i;
        new Thread(() -> {
            try {
                semaphore.acquire();
                System.out.println("thread" + threadNum + ":entered");
                Thread.sleep(1000 * threadNum);
                System.out.println("thread" + threadNum + ":gone");
                semaphore.release();
            } catch (InterruptedException e) {
                System.out.println("thread" + threadNum + ":exception");
            }
        }).start();
    }
}

看一下輸出結(jié)果:

thread2:entered
thread3:entered
thread1:entered
thread1:gone
thread4:entered
thread2:gone
thread5:entered
thread3:gone
thread4:gone
thread5:gone

Process finished with exit code 0

首先我們new了一個(gè)信號(hào)量,給了3個(gè)許可,然后在新建5個(gè)線程搶占信號(hào)量。一開始1,2,3號(hào)線程可以拿到許可,然后4號(hào)線程來了,發(fā)現(xiàn)沒有許可了,4號(hào)線程阻塞,直到1號(hào)線程調(diào)用了release后有了許可后,4號(hào)線程被喚醒,以此類推。。。

Semaphore原理

Semaphore和Reentrant一樣分別實(shí)現(xiàn)了公平鎖和非公平鎖,同樣我們看非公平鎖。上Sync內(nèi)部類代碼:

abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 1192457210091910933L;
    
    //構(gòu)造函數(shù),接收許可的個(gè)數(shù)
    Sync(int permits) {
        setState(permits);
    }

    final int getPermits() {
        return getState();
    }

    //共享模式下,非公平鎖搶占
    final int nonfairTryAcquireShared(int acquires) {
        for (;;) {
            int available = getState();
            //可用許可數(shù)量減去申請(qǐng)?jiān)S可數(shù)量
            int remaining = available - acquires;
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                //返回remaining,小于0表示許可數(shù)量不夠,大于0表示許可數(shù)量足夠
                return remaining;
        }
    }

    //共享模式下釋放許可
    protected final boolean tryReleaseShared(int releases) {
        for (;;) {
            int current = getState();
            int next = current + releases;
            if (next < current) // overflow
                throw new Error("Maximum permit count exceeded");
            if (compareAndSetState(current, next))
                return true;
        }
    }

    //減少許可數(shù)量
    final void reducePermits(int reductions) {
        for (;;) {
            int current = getState();
            int next = current - reductions;
            if (next > current) // underflow
                throw new Error("Permit count underflow");
            if (compareAndSetState(current, next))
                return;
        }
    }

    //清空許可數(shù)量
    final int drainPermits() {
        for (;;) {
            int current = getState();
            if (current == 0 || compareAndSetState(current, 0))
                return current;
        }
    }
}

了解了Semaphore對(duì)state的定義后,我們看一下acquire方法,該方法直接調(diào)用了sync的acquireSharedInterruptibly:

public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    //線程中斷標(biāo)志為true,拋出中斷異常
    if (Thread.interrupted())
        throw new InterruptedException();
    //首先嘗試獲取需要的許可數(shù)量
    if (tryAcquireShared(arg) < 0)
        //當(dāng)獲取失敗
        doAcquireSharedInterruptibly(arg);
}

doAcquireSharedInterruptibly在CountdownLatch里分析過:當(dāng)獲取許可失敗時(shí),往等待隊(duì)列添加當(dāng)前線程的node,如果隊(duì)列沒有初始化則初始化。然后在一個(gè)loop里從隊(duì)列head后第一個(gè)node開始嘗試獲取許可,為了不讓CPU空轉(zhuǎn),當(dāng)head后第一個(gè)node嘗試獲取許可失敗的時(shí)候,阻塞當(dāng)前線程,第一個(gè)node后的弄的一樣都阻塞,等待被喚醒。

private void doAcquireSharedInterruptibly(int arg)
    throws InterruptedException {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}  

當(dāng)調(diào)用了release方法后,意味著有新的許可被釋放,調(diào)用sync的releaseShared,接著調(diào)用Semaphore的內(nèi)部類Sync實(shí)現(xiàn)的tryReleaseShared嘗試釋放許可。釋放成功后調(diào)用AQS的doReleaseShared,在CountdownLatch中也見過這個(gè)方法。在之前head后第一個(gè)node線程阻塞之前,已經(jīng)將head狀態(tài)設(shè)置為SIGNAL,所以會(huì)喚醒第一個(gè)node的線程,該線程繼續(xù)執(zhí)行之前的loop,嘗試獲取許可成功,并且當(dāng)還有剩余的許可存在時(shí)向后傳播喚醒信號(hào),喚醒后繼node的線程,獲取剩余的許可。

總結(jié)

Semaphore和CountdownLatch一樣使用了AQS的共享模式;
Semaphore在有許可釋放時(shí)喚醒第一個(gè)node的線程獲取許可,之后會(huì)根據(jù)是否還存在許可來決定是否繼續(xù)往后傳播喚醒線程的信號(hào)。
CountdownLatch在state為0的時(shí)候依次往后傳播喚醒信號(hào),一直傳播到低,直到所有線程被喚醒。

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

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

相關(guān)文章

  • AbstractQueuedSynchronizer理解之三Semaphore

    摘要:信號(hào)可以理解為一種許可,拿到許可的線程才可以繼續(xù)執(zhí)行。的計(jì)數(shù)器其實(shí)記錄的就是許可的數(shù)量,當(dāng)許可數(shù)量為時(shí),方法就會(huì)阻塞。 本文接著分析Semaphore的實(shí)現(xiàn)原理 Semaphore是什么 Semaphore是一個(gè)計(jì)數(shù)信號(hào)量。Semaphore(信號(hào))可以理解為一種許可,拿到許可的線程才可以繼續(xù)執(zhí)行。Semaphore的計(jì)數(shù)器其實(shí)記錄的就是許可的數(shù)量,當(dāng)許可數(shù)量為0時(shí),acquire方法...

    MingjunYang 評(píng)論0 收藏0
  • AbstractQueuedSynchronizer理解之三Semaphore

    摘要:信號(hào)可以理解為一種許可,拿到許可的線程才可以繼續(xù)執(zhí)行。的計(jì)數(shù)器其實(shí)記錄的就是許可的數(shù)量,當(dāng)許可數(shù)量為時(shí),方法就會(huì)阻塞。 本文接著分析Semaphore的實(shí)現(xiàn)原理 Semaphore是什么 Semaphore是一個(gè)計(jì)數(shù)信號(hào)量。Semaphore(信號(hào))可以理解為一種許可,拿到許可的線程才可以繼續(xù)執(zhí)行。Semaphore的計(jì)數(shù)器其實(shí)記錄的就是許可的數(shù)量,當(dāng)許可數(shù)量為0時(shí),acquire方法...

    zollero 評(píng)論0 收藏0
  • AbstractQueuedSynchronizer 原理分析 - 獨(dú)占/共享模式

    摘要:簡介抽象隊(duì)列同步器,以下簡稱出現(xiàn)在中,由大師所創(chuàng)作。獲取成功則返回,獲取失敗,線程進(jìn)入同步隊(duì)列等待。響應(yīng)中斷版的超時(shí)響應(yīng)中斷版的共享式獲取同步狀態(tài),同一時(shí)刻可能會(huì)有多個(gè)線程獲得同步狀態(tài)。 1.簡介 AbstractQueuedSynchronizer (抽象隊(duì)列同步器,以下簡稱 AQS)出現(xiàn)在 JDK 1.5 中,由大師 Doug Lea 所創(chuàng)作。AQS 是很多同步器的基礎(chǔ)框架,比如 ...

    pf_miles 評(píng)論0 收藏0
  • AbstractQueuedSynchronizer 原理分析 - 獨(dú)占/共享模式

    摘要:簡介抽象隊(duì)列同步器,以下簡稱出現(xiàn)在中,由大師所創(chuàng)作。獲取成功則返回,獲取失敗,線程進(jìn)入同步隊(duì)列等待。響應(yīng)中斷版的超時(shí)響應(yīng)中斷版的共享式獲取同步狀態(tài),同一時(shí)刻可能會(huì)有多個(gè)線程獲得同步狀態(tài)。 1.簡介 AbstractQueuedSynchronizer (抽象隊(duì)列同步器,以下簡稱 AQS)出現(xiàn)在 JDK 1.5 中,由大師 Doug Lea 所創(chuàng)作。AQS 是很多同步器的基礎(chǔ)框架,比如 ...

    gekylin 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<