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

一站式了解Java中Semaphore的基本用法

 更新時(shí)間:2026年02月09日 10:52:32   作者:想用offer打牌  
本文主要介紹了一站式了解Java中Semaphore的基本用法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

引言

我們今天一起來了解一下JUC的同步工具類-Semaphore的基本用法。

什么是Semaphore(信號(hào)量)

Semaphore (信號(hào)量)java.util.concurrent 包下非常有用的一個(gè)并發(fā)工具類。你可以把它理解為用于控制同時(shí)訪問特定資源的線程數(shù)量的工具。它維護(hù)了一組“許可”(permits),線程在訪問受保護(hù)資源前必須先獲取一個(gè)許可,使用完后再釋放該許可。

場(chǎng)景引入

想象一個(gè)只有 5 個(gè)車位的停車場(chǎng)(共享資源):

  1. Permits (許可證/令牌): 初始化時(shí),Semaphore 擁有 5 個(gè)令牌。
  2. Acquire (獲取): 車輛(線程)進(jìn)入時(shí),先領(lǐng) 1 個(gè)令牌。如果沒有令牌了(計(jì)數(shù)為0),車輛就得在門口排隊(duì)(阻塞)。
  3. Release (釋放): 車輛離開時(shí),歸還 1 個(gè)令牌。此時(shí)如果有排隊(duì)的車輛,就會(huì)喚醒其中一個(gè)進(jìn)入。

這就是Semaphore做的事,控制在一個(gè)時(shí)間段內(nèi)可以訪問特定資源的線程數(shù)量。

基本概念

  • 許可(Permit) :Semaphore 內(nèi)部維護(hù)一個(gè)計(jì)數(shù)器,表示當(dāng)前可用的許可數(shù)量。
  • acquire() :嘗試獲取一個(gè)或多個(gè)許可。如果沒有足夠許可,線程會(huì)被阻塞,直到有足夠許可可用。
  • release() :釋放一個(gè)或多個(gè)許可,增加可用許可數(shù)量,可能喚醒等待中的線程。

底層原理

Semaphore 內(nèi)部基于 AQS (AbstractQueuedSynchronizer) 實(shí)現(xiàn)。

  • 它使用 AQS 的 state 變量來存儲(chǔ)當(dāng)前的許可證數(shù)量。
  • acquire() 操作是對(duì) state 進(jìn)行 CAS 減法。
  • release() 操作是對(duì) state 進(jìn)行 CAS 加法。

常用方法

下面是Semaphore的常用方法。

方法描述場(chǎng)景
new Semaphore(int permits)創(chuàng)建非公平信號(hào)量(默認(rèn))。吞吐量?jī)?yōu)先
new Semaphore(int permits, boolean fair)創(chuàng)建公平信號(hào)量(FIFO)。避免線程饑餓
acquire()獲取1個(gè)許可,若無則阻塞。響應(yīng)中斷。必須拿到的場(chǎng)景
acquire(int n)一次獲取 n 個(gè)許可。批量資源
tryAcquire()嘗試獲取,成功返回 true,失敗返回 false,不阻塞。快速失敗/降級(jí)處理
tryAcquire(long timeout, TimeUnit unit)帶超時(shí)的嘗試獲取。避免長(zhǎng)時(shí)間死等
release()釋放1個(gè)許可。務(wù)必在 finally 中調(diào)用
void release(int permits)釋放指定數(shù)量許可。務(wù)必在 finally 中調(diào)用

使用例子

這是最典型的使用場(chǎng)景:限流 (Rate Limiting)資源池控制。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SemaphoreExample {

    // 定義一個(gè)只能允許3個(gè)線程同時(shí)訪問的信號(hào)量
    private static final Semaphore semaphore = new Semaphore(3);

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(10);

        // 模擬10個(gè)請(qǐng)求同時(shí)涌入
        for (int i = 0; i < 10; i++) {
            final int threadNum = i;
            executor.execute(() -> {
                try {
                    // 1. 獲取許可 (如果拿不到,這里會(huì)阻塞)
                    // 也可以使用 tryAcquire() 來進(jìn)行非阻塞嘗試
                    semaphore.acquire(); 
                    
                    System.out.println("線程 " + threadNum + " 拿到了令牌,正在處理業(yè)務(wù)...");
                    // 模擬業(yè)務(wù)耗時(shí)
                    TimeUnit.SECONDS.sleep(2); 
                    
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    // 2. 關(guān)鍵:一定要在 finally 中釋放許可!
                    System.out.println("線程 " + threadNum + " 處理完畢,歸還令牌 ---");
                    semaphore.release(); 
                }
            });
        }
        executor.shutdown();
    }
}

一般使用場(chǎng)景有這些,特別是框架特別喜歡用:

  • 數(shù)據(jù)庫連接池(限制最大連接數(shù))
  • 線程池任務(wù)提交限流
  • 文件讀寫并發(fā)控制
  • 服務(wù)接口的 QPS 限流

平時(shí)使用的坑你要注意

場(chǎng)景 A:公平性 (Fairness)

new Semaphore(3, true) 會(huì)保證等待最久的線程最先拿到令牌。

  • 優(yōu)點(diǎn): 避免線程饑餓。
  • 缺點(diǎn): 性能較差(因?yàn)橐S護(hù)嚴(yán)格的隊(duì)列順序,增加了上下文切換開銷)。通常后端高并發(fā)場(chǎng)景默認(rèn)使用非公平模式以換取吞吐量。

場(chǎng)景 B:初始化為 0

Semaphore 不一定要初始化為正數(shù)。如果你初始化為 new Semaphore(0)

  • 線程 A 調(diào)用 acquire() 會(huì)立刻阻塞。
  • 直到線程 B 調(diào)用 release(),線程 A 才會(huì)繼續(xù)執(zhí)行。
  • 用途: 這種模式類似 CountDownLatchExchanger,用于線程間的單次信號(hào)通知。

常見坑

  1. 忘記 Release: 如果在異常發(fā)生前沒有釋放,或者沒寫在 finally 塊中,在這個(gè) JVM 進(jìn)程重啟前,那個(gè)令牌就永久丟失了(類似內(nèi)存泄漏),最終導(dǎo)致所有線程阻塞。所以千萬要記住,寫release在finally塊?。?/li>
  2. Release 濫用: release() 只是簡(jiǎn)單地將計(jì)數(shù)器 +1。如果你在沒有 acquire 的情況下錯(cuò)誤地調(diào)用了多次 release(),信號(hào)量的許可證數(shù)量會(huì)超過初始值(比如變成 5+1 = 6),導(dǎo)致限流失效。

和平時(shí)的ReentrantLock / synchronized 的區(qū)別

使用用途和目的是它們最大的區(qū)別。

特性synchronized / ReentrantLockSemaphore
控制粒度一次只允許一個(gè)線程進(jìn)入臨界區(qū)可允許多個(gè)線程(≤許可數(shù))同時(shí)進(jìn)入
是否可重入是(ReentrantLock)否(許可不屬于特定線程)
主要用途互斥訪問資源池、限流、并發(fā)控制

那么使用自定義計(jì)時(shí)器+鎖+喚醒等待機(jī)制也是可以實(shí)現(xiàn)Semaphore一樣的功能,但是沒必要,還容易出錯(cuò)。不如直接使用Semaphore。

總結(jié)

Semaphore就是用來限制同時(shí)訪問統(tǒng)一資源的工具。

除了平時(shí)開發(fā)使用到Semaphore,我們平時(shí)面試做有關(guān)于多線程的算法題也有可能用到噢,所以還是非常有必要熟悉Semaphore的。

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

相關(guān)文章

  • Spring?Boot自動(dòng)配置源碼實(shí)例解析

    Spring?Boot自動(dòng)配置源碼實(shí)例解析

    Spring Boot作為Java領(lǐng)域最為流行的快速開發(fā)框架之一,其核心特性之一就是其強(qiáng)大的自動(dòng)配置機(jī)制,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot自動(dòng)配置源碼的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-08-08
  • java讀取文件內(nèi)容,解析Json格式數(shù)據(jù)方式

    java讀取文件內(nèi)容,解析Json格式數(shù)據(jù)方式

    這篇文章主要介紹了java讀取文件內(nèi)容,解析Json格式數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 解決static類使用@Value獲取yml文件獲取不到的問題

    解決static類使用@Value獲取yml文件獲取不到的問題

    在靜態(tài)類中直接使用@Value注解無法獲取yml文件中的配置,解決方案是在工具類Utils中創(chuàng)建靜態(tài)的setter方法,并從外部類ServiceClass中調(diào)用這個(gè)方法來設(shè)置值,這種方法通過外部調(diào)用來間接設(shè)置靜態(tài)變量的值,從而成功讀取yml配置
    2024-09-09
  • java datetime數(shù)據(jù)類型去掉時(shí)分秒的案例詳解

    java datetime數(shù)據(jù)類型去掉時(shí)分秒的案例詳解

    在Java中,如果我們想要表示一個(gè)日期而不包括時(shí)間(時(shí)分秒),我們通常會(huì)使用java.time包中的LocalDate類,這篇文章主要介紹了java datetime數(shù)據(jù)類型去掉時(shí)分秒,需要的朋友可以參考下
    2024-06-06
  • java獲取指定開始時(shí)間與結(jié)束時(shí)間之間的所有日期

    java獲取指定開始時(shí)間與結(jié)束時(shí)間之間的所有日期

    這篇文章主要為大家詳細(xì)介紹了java獲取指定開始時(shí)間與結(jié)束時(shí)間之間的所有日期,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • java中MultipartFile類型轉(zhuǎn)為File類型的4種方法

    java中MultipartFile類型轉(zhuǎn)為File類型的4種方法

    Spring提供了一個(gè)MultipartFile接口來處理文件上傳,但有時(shí)候我們需要將MultipartFile轉(zhuǎn)換為File來進(jìn)行一些特定的操作,比如保存文件到本地或者進(jìn)行文件的處理等,這篇文章主要給大家介紹了關(guān)于java中MultipartFile類型轉(zhuǎn)為File類型的4種方法,需要的朋友可以參考下
    2024-09-09
  • Java中的Set、List、Map的用法與區(qū)別介紹

    Java中的Set、List、Map的用法與區(qū)別介紹

    這篇文章主要介紹了Java中的Set、List、Map的用法與區(qū)別,需要的朋友可以參考下
    2016-06-06
  • springAOP的三種實(shí)現(xiàn)方式示例代碼

    springAOP的三種實(shí)現(xiàn)方式示例代碼

    這篇文章主要介紹了springAOP的三種實(shí)現(xiàn)方式,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Java把Map轉(zhuǎn)為對(duì)象的實(shí)現(xiàn)代碼

    Java把Map轉(zhuǎn)為對(duì)象的實(shí)現(xiàn)代碼

    在項(xiàng)目開發(fā)中,經(jīng)常碰到map轉(zhuǎn)實(shí)體對(duì)象或者對(duì)象轉(zhuǎn)map的場(chǎng)景,工作中,很多時(shí)候我們可能比較喜歡使用第三方j(luò)ar包的API對(duì)他們進(jìn)行轉(zhuǎn)化,但這里,我想通過反射的方式對(duì)他們做轉(zhuǎn)化,感興趣的同學(xué)跟著小編來看看吧
    2023-08-08
  • Java簡(jiǎn)單計(jì)算圓周率完整示例

    Java簡(jiǎn)單計(jì)算圓周率完整示例

    這篇文章主要介紹了Java簡(jiǎn)單計(jì)算圓周率,結(jié)合完整實(shí)例形式分析了Java計(jì)算圓周率的原理與操作技巧,代碼備有較為詳盡的注釋便于理解,需要的朋友可以參考下
    2018-05-05

最新評(píng)論

西和县| 临城县| 西乡县| 斗六市| 怀来县| 宁远县| 阜新市| 镇雄县| 湘西| 浦县| 白河县| 英超| 沈丘县| 高邮市| 井陉县| 顺昌县| 偃师市| 浦江县| 大城县| 惠州市| 两当县| 田阳县| 禹州市| 奇台县| 保德县| 东乡族自治县| 忻州市| 老河口市| 惠来县| 娄烦县| 长丰县| 抚州市| 获嘉县| 公主岭市| 沾化县| 临泉县| 通许县| 阿城市| 大悟县| 扎鲁特旗| 商丘市|