最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的Semaphore原理解析

 更新時(shí)間:2024年01月22日 10:28:32   作者:我不是歐拉_  
這篇文章主要介紹了Java中的Semaphore原理解析,Semaphore(信號量)是用來控制同時(shí)訪問特定資源的線程數(shù)量,它通過協(xié)調(diào)各個(gè)線程,以保證合理的使用公共資源,需要的朋友可以參考下

1. Semaphore是什么?

Semaphore(信號量)是用來控制同時(shí)訪問特定資源的線程數(shù)量,它通過協(xié)調(diào)各個(gè)線程,以保證合理的使用公共資源。

Semaphore一般用于流量的控制,特別是公共資源有限的應(yīng)用場景。例如數(shù)據(jù)庫的連接,假設(shè)數(shù)據(jù)庫的連接數(shù)上線為10個(gè),多個(gè)線程并發(fā)操作數(shù)據(jù)庫可以使用Semaphore來控制并發(fā)操作數(shù)據(jù)庫的線程個(gè)數(shù)最多為10個(gè)。

2. 類圖

通過類圖可以看到,Semaphore與ReentrantLock的內(nèi)部類的結(jié)構(gòu)相同,類內(nèi)部總共存在Sync、NonfairSync、FairSync三個(gè)類,NonfairSync與FairSync類繼承自Sync類,Sync類繼承自AbstractQueuedSynchronizer抽象類。 

3. 實(shí)現(xiàn)原理

3.1 使用示例

    // 定義一個(gè)資源池類
    class Pool {
        // 可用資源數(shù)100
        private static final int MAX_AVAILABLE = 100;
        // 定義信號量100
        private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
        // 獲取資源
        public Object getItem() throws InterruptedException {
            // 嘗試獲取
            available.acquire();
            // 返回可用資源
            return getNextAvailableItem();
        }
        // 釋放資源
        public void putItem(Object x) {
            // 如果資源標(biāo)記為未被使用
            if (markAsUnused(x))
            // 釋放資源
            available.release();
        }
        // Not a particularly efficient data structure; just for demo
        // 定義資源類型,可以是滿足業(yè)務(wù)的任何類型
        protected Object[] items = new Object[MAX_AVAILABLE] ... whatever kinds of items being managed
        // 是否被使用標(biāo)記
        protected boolean[] used = new boolean[MAX_AVAILABLE];
        // 獲取下一個(gè)可用資源
        protected synchronized Object getNextAvailableItem() {
            // 循環(huán)遍歷
            for (int i = 0; i < MAX_AVAILABLE; ++i) {
                // 如果未被使用
                if (!used[i]) {
                    // 使用標(biāo)記設(shè)置為true
                    used[i] = true;
                    // 返回當(dāng)前的資源
                    return items[i];
                }
            }
            return null; // not reached
        }
        // 標(biāo)記資源為未被使用
        protected synchronized boolean markAsUnused(Object item) {
            // 循環(huán)遍歷
            for (int i = 0; i < MAX_AVAILABLE; ++i) {
                // 找到需要釋放的資源
                if (item == items[i]) {
                    // 如果是被使用中
                    if (used[i]) {
                    // 使用標(biāo)記設(shè)置為false
                    used[i] = false;
                    // 返回true表示標(biāo)記成功
                    return true;
                } else
                    // 返回false表示標(biāo)記失敗
                    return false;
                }
            }
            return false;
        }
    }

3.2 Sync

abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;
        // 構(gòu)造方法,調(diào)用父類AQS的setState方法,給共享變量state賦值
        // 即通過構(gòu)造方法給鎖的數(shù)量附初始值
        Sync(int permits) {
            setState(permits);
        }
        // 獲取鎖,也叫許可
        final int getPermits() {
            return getState();
        }
        // 共享模式下的非公平獲取
        // 此方法也體現(xiàn)出與ReentrantLock中Sync的實(shí)現(xiàn)不同
        // ReentrantLock中Sync是獨(dú)占模式下的獲取
        // 具體實(shí)現(xiàn)的不同體現(xiàn)在int remaining = available - acquires;
        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                // 獲取鎖的可用數(shù)量
                int available = getState();
                // 可用數(shù)量 - 請求的數(shù)量(acquires默認(rèn)值為1) = 剩余量
                int remaining = available - acquires;
                // 如果remaining < 0即請求的鎖大于可用的數(shù)量,馬上返回負(fù)數(shù),表示獲取鎖失敗
                if (remaining < 0 ||
                    // 否則通過CAS的方式將可用數(shù)量換成剩余量,并返回剩余量
                    // 自旋 + CAS 保證線程安全,線程不用排隊(duì)體現(xiàn)出非公平性
                    compareAndSetState(available, remaining))
                    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");
                // CAS修改鎖數(shù)量,成功則返回,失敗則繼續(xù)自旋
                if (compareAndSetState(current, next))
                    return true;
            }
        }
        // 根據(jù)指定的縮減量減小可用鎖的數(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;
            }
        }
        // 獲取并返回立即可用的所有鎖
        final int drainPermits() {
            for (;;) {
                int current = getState();
                if (current == 0 || compareAndSetState(current, 0))
                    return current;
            }
        }
    }

3.3 NonfairSync

static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;
        // 構(gòu)造方法初始化鎖數(shù)量
        NonfairSync(int permits) {
            super(permits);
        }
        // 直接調(diào)用nonfairTryAcquireShared方法,走非公平策略
        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }

3.4 FairSync

static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;
        // 構(gòu)造方法初始化鎖數(shù)量
        FairSync(int permits) {
            super(permits);
        }
        // 共享模式下的公平策略獲取
        // 與非公平策略唯一的不同體現(xiàn)在線程是否需要排隊(duì)
        // 即是否調(diào)用hasQueuedPredecessors()方法進(jìn)行判斷
        // 如果需要排隊(duì)則立即返回繼續(xù)排隊(duì)
        // 否則通過CAS方式獲取鎖并返貨鎖的剩余量,結(jié)束自旋
        protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }

通過分析代碼發(fā)現(xiàn),Semaphore與ReentrantLock的內(nèi)部類的結(jié)構(gòu)相同,具體實(shí)現(xiàn)的不同體現(xiàn)在 int remaining = available - acquires這行代碼上。

ReentrantLock對于鎖的控制是 int c = getState(); if (c == 0){....}。體現(xiàn)為一種獨(dú)占的控制。

Semaphore對鎖的控制是 for (;;) { int available = getState(); int remaining = available - acquires;......}。即所有線程都可以進(jìn)入自旋,只要鎖有剩余量都可以嘗試獲取鎖,體現(xiàn)為一種共享的控制。

3.5 Semaphore

public class Semaphore implements java.io.Serializable {
    private static final long serialVersionUID = -3222578661600680210L;
    /** All mechanics via AbstractQueuedSynchronizer subclass */
    // 同步隊(duì)列
    private final Sync sync;
    // 構(gòu)造方法初始話鎖數(shù)量
    // 默認(rèn)采用非公平策略
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }
    // 構(gòu)造方法,帶一個(gè)布爾參數(shù),true表示采用公平策略,false表示采用非公平策略
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
}

3.5.1 acquire() 方法解析

// Semaphore
public void acquire() throws InterruptedException {
        // 調(diào)用sync的acquireSharedInterruptibly,即響應(yīng)中斷的獲取
        // 因?yàn)閟ync繼承AbstractQueuedSynchronizer
        // 即調(diào)用AQS的acquireSharedInterruptibly
        sync.acquireSharedInterruptibly(1);
    }
// 進(jìn)入AQS
public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        // 如果線程被中斷,則響應(yīng)中斷
        if (Thread.interrupted())
            throw new InterruptedException();
        // 否則調(diào)用tryAcquireShared,如果獲取的鎖小于0即獲取鎖失敗則調(diào)用doAcquireSharedInterruptibly方法,進(jìn)入同步隊(duì)列排隊(duì)
        // 如果獲取鎖成功則不排隊(duì),走業(yè)務(wù)邏輯
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
// Semaphore 中tryAcquireShared的實(shí)現(xiàn)
// 公平策略
protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
// 非公平策略
protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
// 前面已經(jīng)解析過,不在贅述
 

3.5.2 release() 方法解析

// Semaphore
public void release() {
        sync.releaseShared(1);
    }
// 進(jìn)入AQS
public final boolean releaseShared(int arg) {
        // 嘗試釋放鎖, 如果釋放鎖成功
        if (tryReleaseShared(arg)) {
            // 線程出同步隊(duì)列,返回true
            doReleaseShared();
            return true;
        }
        // 否則返回false
        return false;
    }
// Semaphore 中tryReleaseShared實(shí)現(xiàn)
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;
            }
        }

3.5.3 其他方法

方法說明調(diào)用
acquire(int permits)獲取信號量,指定獲取許可的個(gè)數(shù),響應(yīng)中斷sync.acquireSharedInterruptibly(permits)
acquireUninterruptibly()獲取信號量,默認(rèn)獲取1個(gè)許可,不響應(yīng)中斷sync.acquireShared(1)
acquireUninterruptibly(int permits)獲取信號量,指定獲取許可的個(gè)數(shù),不響應(yīng)中斷sync.acquireShared(permits)
release(int permits)釋放信號量,指定釋放許可的個(gè)數(shù)sync.releaseShared(permits);
tryAcquire()嘗試獲取許可,如果獲取成功返回true,否則返回false,不會(huì)阻塞線程,而且不響應(yīng)中斷sync.nonfairTryAcquireShared(1)
tryAcquire(int permits)同上,可以指定獲取許可的個(gè)數(shù)sync.nonfairTryAcquireShared(permits)
tryAcquire(long timeout, TimeUnit unit)共享式超時(shí)獲取sync.tryAcquireSharedNanos(1, unit.toNanos(timeout))
tryAcquire(int permits, long timeout, TimeUnit unit)同上,可以指定獲取許可的個(gè)數(shù)sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout))
availablePermits()獲取可用許可數(shù)sync.getPermits()
drainPermits()將剩下的信號量一次性消耗光,并且返回所消耗的信號量sync.drainPermits()
reducePermits(int reduction)減少信號量的總數(shù),不會(huì)導(dǎo)致任何線程阻塞,調(diào)用該方法可能會(huì)導(dǎo)致信號量最終為負(fù)數(shù)sync.reducePermits(reduction)
isFair()是否采用公平策略
hasQueuedThreads()是否是已排隊(duì)的線程
getQueueLength()獲取排隊(duì)線程的長度
getQueuedThreads()獲取排隊(duì)線程

4. 總結(jié)

Semaphore是一個(gè)有效的流量控制工具,它基于AQS共享鎖實(shí)現(xiàn)。我們常常用它來控制對有限資源的訪問。使用步驟

每次使用資源前,先申請一個(gè)信號量,如果資源數(shù)不夠,就會(huì)阻塞等待;每次釋放資源后,就釋放一個(gè)信號量。

到此這篇關(guān)于Java中的Semaphore原理解析的文章就介紹到這了,更多相關(guān)Semaphore原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java淺析枚舉類的使用

    Java淺析枚舉類的使用

    枚舉類型可以取代以往常量的定義方式,即將常量封裝在類或接口中。此外,枚舉類型還提供了安全檢查功能。本文就來和大家講講Java中枚舉類的用法,需要的可以參考一下
    2022-07-07
  • Java技術(shù)匯總

    Java技術(shù)匯總

    本篇文章主要對Java基本知識(shí)點(diǎn)和技術(shù)點(diǎn)的一些看法和介紹,具有很好的參考價(jià)值。下面跟著小編一起來看下吧
    2017-03-03
  • mybatis group by substr函數(shù)傳參報(bào)錯(cuò)的解決

    mybatis group by substr函數(shù)傳參報(bào)錯(cuò)的解決

    這篇文章主要介紹了mybatis group by substr函數(shù)傳參報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • SpringBoot中POST請求參數(shù)校驗(yàn)的實(shí)戰(zhàn)指南

    SpringBoot中POST請求參數(shù)校驗(yàn)的實(shí)戰(zhàn)指南

    在現(xiàn)代的Web開發(fā)中,數(shù)據(jù)校驗(yàn)是確保應(yīng)用程序穩(wěn)定性和安全性的關(guān)鍵環(huán)節(jié),Spring Boot提供了強(qiáng)大而靈活的校驗(yàn)機(jī)制,能夠幫助開發(fā)者輕松地對POST請求參數(shù)進(jìn)行校驗(yàn),本文將詳細(xì)介紹如何在Spring Boot中實(shí)現(xiàn)POST請求參數(shù)的校驗(yàn),需要的朋友可以參考下
    2025-07-07
  • SWT(JFace) FTP客戶端實(shí)現(xiàn)

    SWT(JFace) FTP客戶端實(shí)現(xiàn)

    SWT(JFace)小制作:FTP客戶端實(shí)現(xiàn)
    2009-06-06
  • 一文帶你深入了解SpringBoot參數(shù)配置的詳細(xì)步驟

    一文帶你深入了解SpringBoot參數(shù)配置的詳細(xì)步驟

    SpringBoot應(yīng)用就像一個(gè)超級智能的變形金剛,而參數(shù)配置就是你手里的萬能遙控器,下面小編就和大家詳細(xì)介紹一下SpringBoot參數(shù)配置的相關(guān)應(yīng)用,感興趣的小伙伴可以了解下
    2025-12-12
  • java實(shí)現(xiàn)上傳和下載工具類

    java實(shí)現(xiàn)上傳和下載工具類

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)上傳和下載工具類,文件上傳到ftp服務(wù)工具類,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Java實(shí)現(xiàn)局域網(wǎng)聊天小程序

    Java實(shí)現(xiàn)局域網(wǎng)聊天小程序

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)局域網(wǎng)聊天小程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Java超詳細(xì)分析垃圾回收機(jī)制

    Java超詳細(xì)分析垃圾回收機(jī)制

    一個(gè)運(yùn)行中的程序,?產(chǎn)生的對象是大量的,?如果對象不被繼續(xù)使用,?就會(huì)成為垃圾,?最后越堆越多,?最后占滿內(nèi)存,?所以我們要對這些垃圾進(jìn)行回收,保持程序的正常運(yùn)行
    2022-05-05
  • Springboot之修改啟動(dòng)端口的兩種方式(小結(jié))

    Springboot之修改啟動(dòng)端口的兩種方式(小結(jié))

    這篇文章主要介紹了Springboot之修改啟動(dòng)端口的兩種方式(小結(jié)),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09

最新評論

西藏| 清新县| 佛学| 响水县| 利津县| 泸州市| 盐边县| 禹州市| 嘉荫县| 兴海县| 桃源县| 弥渡县| 城口县| 青田县| 闻喜县| 宾川县| 含山县| 长海县| 新龙县| 林西县| 铜梁县| 元氏县| 东莞市| 桃园市| 宣汉县| 深州市| 合山市| 湘西| 休宁县| 略阳县| 五莲县| 聂拉木县| 新津县| 类乌齐县| 如东县| 岑巩县| 泰来县| 登封市| 资源县| 兰州市| 新和县|