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

Java的Semaphore信號量使用及原理解讀

 更新時間:2023年12月28日 09:51:36   作者:一個風輕云淡  
這篇文章主要介紹了Java的Semaphore信號量使用及原理解讀,Semaphore(信號量)是Java中一個并發(fā)控制工具,用于控制對共享資源的訪問,它基于計數(shù)器的原理,可以限制同時訪問某個資源的線程數(shù)量,需要的朋友可以參考下

概述

Semaphore(信號量)是Java中一個并發(fā)控制工具,用于控制對共享資源的訪問。它基于計數(shù)器的原理,可以限制同時訪問某個資源的線程數(shù)量。

在Java中使用Semaphore,你需要按照以下步驟進行操作:

導包: 

import java.util.concurrent.Semaphore;

 創(chuàng)建Semaphore對象:

Semaphore semaphore = new Semaphore(n);

其中,n是允許同時訪問共享資源的線程數(shù)量。

在需要訪問共享資源的代碼段前后,使用acquire()和release()方法來獲取和釋放信號量:

try {
    semaphore.acquire(); // 獲取信號量,如果沒有可用的許可證,線程將被阻塞
    // 訪問共享資源的代碼
} catch (InterruptedException e) {
    // 處理中斷異常
} finally {
    semaphore.release(); // 釋放信號量,增加一個許可證
}

acquire()方法嘗試獲取一個許可證,如果當前沒有可用的許可證,則該線程將被阻塞,直到有可用的許可證為止。release()方法釋放一個許可證,使其可供其他線程使用。

通過適當?shù)厥褂胊cquire()和release()方法,在超過信號量允許的線程數(shù)量時,可以限制并發(fā)訪問共享資源的線程數(shù)量,實現(xiàn)線程間的同步和互斥。

需要注意的是,Semaphore還提供了一些其他方法,如availablePermits()用于獲取當前可用的許可證數(shù)量,以及tryAcquire()方法在不阻塞線程的情況下嘗試獲取許可證等。

具體例子 

    public static void main(String[] args) {
        // 1. 創(chuàng)建 semaphore 對象
        Semaphore semaphore = new Semaphore(3);
        // 2. 10個線程同時運行
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                // 3. 獲取許可
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    log.debug("running...");
                    sleep(1);
                    log.debug("end...");
                } finally {
                    // 4. 釋放許可
                    semaphore.release();
                }
            }).start();
        }
    }

07:35:15.485 c.TestSemaphore [Thread-2] - running...

07:35:15.485 c.TestSemaphore [Thread-1] - running...

07:35:15.485 c.TestSemaphore [Thread-0] - running...

07:35:16.490 c.TestSemaphore [Thread-2] - end...

07:35:16.490 c.TestSemaphore [Thread-0] - end...

07:35:16.490 c.TestSemaphore [Thread-1] - end...

07:35:16.490 c.TestSemaphore [Thread-3] - running...

07:35:16.490 c.TestSemaphore [Thread-5] - running...

07:35:16.490 c.TestSemaphore [Thread-4] - running...

07:35:17.490 c.TestSemaphore [Thread-5] - end...

07:35:17.490 c.TestSemaphore [Thread-4] - end...

07:35:17.490 c.TestSemaphore [Thread-3] - end...

07:35:17.490 c.TestSemaphore [Thread-6] - running...

07:35:17.490 c.TestSemaphore [Thread-7] - running...

07:35:17.490 c.TestSemaphore [Thread-9] - running...

07:35:18.491 c.TestSemaphore [Thread-6] - end...

07:35:18.491 c.TestSemaphore [Thread-7] - end...

07:35:18.491 c.TestSemaphore [Thread-9] - end...

07:35:18.491 c.TestSemaphore [Thread-8] - running...

07:35:19.492 c.TestSemaphore [Thread-8] - end...  

源碼原理解析

加鎖解鎖流程原理

Semaphore 有點像一個停車場,permits 就好像停車位數(shù)量,當線程獲得了 permits 就像是獲得了停車位,然后 停車場顯示空余車位減一 剛開始,permits(state)為 3,這時 5 個線程來獲取資源

假設其中 Thread-1,Thread-2,Thread-4 cas 競爭成功,而 Thread-0 和 Thread-3 競爭失敗,進入 AQS 隊列park 阻塞

接下來 Thread-0 競爭成功,permits 再次設置為 0,設置自己為 head 節(jié)點,斷開原來的 head 節(jié)點,unpark 接 下來的 Thread-3 節(jié)點,但由于 permits 是 0,因此 Thread-3 在嘗試不成功后再次進入 park 狀態(tài)

源碼 

 構造方法有倆個: 

  public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

創(chuàng)建 Semaphore 具有給定數(shù)量的許可和不公平公平設置。 參數(shù): 許可證 – 可用的許可證的初始數(shù)量。此值可能為負數(shù),在這種情況下,必須先進行釋放,然后才能授予任何收購。 

    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

創(chuàng)建具有給定數(shù)量的許可和給定公平性設置的 。

Semaphore 參數(shù):

許可證 – 可用的許可證的初始數(shù)量。此值可能為負數(shù),在這種情況下,必須先進行釋放,然后才能授予任何收購。

公平 – true 如果此信號量將保證在爭用中授予先進先出的許可證,否則 false 

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;
 
        NonfairSync(int permits) {
            // permits 即 state
 
            super(permits);
        }
 
        // Semaphore 方法, 方便閱讀, 放在此處
 
        public void acquire() throws InterruptedException {
            sync.acquireSharedInterruptibly(1);
        }
 
        // AQS 繼承過來的方法, 方便閱讀, 放在此處
 
        public final void acquireSharedInterruptibly(int arg)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            if (tryAcquireShared(arg) < 0)
                doAcquireSharedInterruptibly(arg);
        }
 
        // 嘗試獲得共享鎖
 
        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
 
        // Sync 繼承過來的方法, 方便閱讀, 放在此處
 
        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (
                    // 如果許可已經用完, 返回負數(shù), 表示獲取失敗, 進入 doAcquireSharedInterruptibly
 
                        remaining < 0 ||
 
                                // 如果 cas 重試成功, 返回正數(shù), 表示獲取成功
 
                                compareAndSetState(available, remaining)
                ) {
                    return remaining;
                }
            }
        }
 
        // AQS 繼承過來的方法, 方便閱讀, 放在此處
 
        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) {
                            // 成功后本線程出隊(AQS), 所在 Node設置為 head
 
                            // 如果 head.waitStatus == Node.SIGNAL ==> 0 成功, 下一個節(jié)點 unpark
 
                            // 如果 head.waitStatus == 0 ==> Node.PROPAGATE
 
                            // r 表示可用資源數(shù), 為 0 則不會繼續(xù)傳播
 
                            setHeadAndPropagate(node, r);
                            p.next = null; // help GC
 
                            failed = false;
                            return;
                        }
                    }
                    // 不成功, 設置上一個節(jié)點 waitStatus = Node.SIGNAL, 下輪進入 park 阻塞
 
                    if (shouldParkAfterFailedAcquire(p, node) &&
 
                            parkAndCheckInterrupt())
                        throw new InterruptedException();
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
 
        // Semaphore 方法, 方便閱讀, 放在此處
 
        public void release() {
            sync.releaseShared(1);
        }
 
        // AQS 繼承過來的方法, 方便閱讀, 放在此處
 
        public final boolean releaseShared(int arg) {
            if (tryReleaseShared(arg)) {
                doReleaseShared();
                return true;
            }
            return false;
        }
 
        // Sync 繼承過來的方法, 方便閱讀, 放在此處
        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;
            }
        }
    }

到此這篇關于Java的Semaphore信號量使用及原理解讀的文章就介紹到這了,更多相關Semaphore信號量使用及原理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot動態(tài)修改日志級別的操作

    SpringBoot動態(tài)修改日志級別的操作

    這篇文章主要介紹了SpringBoot動態(tài)修改日志級別的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Spring Boot 配置和使用多線程池的實現(xiàn)

    Spring Boot 配置和使用多線程池的實現(xiàn)

    這篇文章主要介紹了Spring Boot 配置和使用多線程池的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • SpringBoot中Token登錄授權、續(xù)期和主動終止的方案流程分析

    SpringBoot中Token登錄授權、續(xù)期和主動終止的方案流程分析

    SpringBoot項目中,基于Token的登錄授權方案主要有兩種:利用Session/Cookie和JWT,Cookie/Session方案有狀態(tài),不適合分布式架構,而JWT雖無狀態(tài),但存在過期時間不可強制失效、一次性等缺點,本文介紹SpringBoot中Token登錄授權、續(xù)期和主動終止的方案,感興趣的朋友一起看看吧
    2024-09-09
  • Java實現(xiàn)自定義中文排序的方法機注意事項

    Java實現(xiàn)自定義中文排序的方法機注意事項

    在Java中,中文排序通常涉及到使用Collator類來處理字符串的比較,確保根據(jù)漢字的拼音順序進行排序,本文給大家介紹了Java實現(xiàn)自定義中文排序的方法機注意事項,并有相關的代碼示例供大家參考,需要的朋友可以參考下
    2024-10-10
  • SpringBoot基于Redis實現(xiàn)生成全局唯一ID的方法

    SpringBoot基于Redis實現(xiàn)生成全局唯一ID的方法

    在項目中生成全局唯一ID有很多好處,生成全局唯一ID有助于提高系統(tǒng)的可用性、數(shù)據(jù)的完整性和安全性,同時也方便數(shù)據(jù)的管理和分析,所以本文給大家介紹了SpringBoot基于Redis實現(xiàn)生成全局唯一ID的方法,文中有詳細的代碼講解,需要的朋友可以參考下
    2023-12-12
  • Spring中@Async用法詳解及簡單實例

    Spring中@Async用法詳解及簡單實例

    這篇文章主要介紹了Spring中@Async用法詳解及簡單實例的相關資料,需要的朋友可以參考下
    2017-02-02
  • 登陸驗證碼kaptcha結合spring boot的用法詳解

    登陸驗證碼kaptcha結合spring boot的用法詳解

    在一個web應用中驗證碼是一個常見的元素。不管是防止機器人還是爬蟲都有一定的作用,下面這篇文章主要給大家介紹了登陸驗證碼kaptcha結合spring boot用法的相關資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-06-06
  • 詳解SpringMVC重定向傳參數(shù)的實現(xiàn)

    詳解SpringMVC重定向傳參數(shù)的實現(xiàn)

    本篇文章主要介紹了詳解SpringMVC重定向傳參數(shù)的實現(xiàn),我們可以使用重定向的方式,改變?yōu)g覽器的地址欄,防止表單因為刷新重復提交。有興趣的可以了解一下。
    2017-01-01
  • java實現(xiàn)桌面右下角彈窗效果

    java實現(xiàn)桌面右下角彈窗效果

    這篇文章主要為大家詳細介紹了java實現(xiàn)桌面右下角彈窗效果,模仿類似于qq消息彈窗,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • java并發(fā)編程死鎖定義及如何避免死鎖

    java并發(fā)編程死鎖定義及如何避免死鎖

    這篇文章主要為大家介紹了java并發(fā)編程中死鎖的詳細說明及如何避免死鎖的方法,有需要的朋友可以借鑒參考下希望能夠有所幫助,祝大家多多進步
    2022-02-02

最新評論

宜阳县| 阳朔县| 沈阳市| 历史| 乌鲁木齐市| 祁阳县| 高唐县| 青河县| 南靖县| 黄石市| 洛扎县| 闽侯县| 平舆县| 巧家县| 苏州市| 萝北县| 肇庆市| 青州市| 巴东县| 门头沟区| 偏关县| 丰镇市| 盈江县| 古田县| 独山县| 岱山县| 霍邱县| 金坛市| 固阳县| 尼木县| 华容县| 大名县| 商水县| 宽甸| 德江县| 罗田县| 洮南市| 嘉义市| 收藏| 梅州市| 延寿县|