JUC之限流利器 Semaphore

如果大家對java架構相關感興趣,可以關注下面公衆號,會持續更新java基礎面試題, netty, spring boot,spring cloud等系列文章,一系列乾貨隨時送達, 超神之路從此展開, BTAJ不再是夢想!

架構殿堂

概念

Semaphore 是一個計數信號量,必須由獲取它的線程釋放。

常用於限制可以訪問某些資源的線程數量,例如通過 Semaphore 限流。

主要方法摘要

// 非公平構造函數 創建具有給定的許可數和非公平的公平設置的 Semaphore。
Semaphore(int permits)
// 公平構造函數 創建具有給定的許可數和給定的公平設置的 Semaphore。
Semaphore(int permits, boolean fair)

// 從此信號量獲取一個許可,在提供一個許可前一直將線程阻塞,否則線程被中斷。
void acquire()
// 從此信號量獲取給定數目的許可,在提供這些許可前一直將線程阻塞,或者線程已被中斷。
void acquire(int permits)
// 從此信號量中獲取許可,在有可用的許可前將其阻塞。
void acquireUninterruptibly()
// 從此信號量獲取給定數目的許可,在提供這些許可前一直將線程阻塞。
void acquireUninterruptibly(int permits)
// 返回此信號量中當前可用的許可數。
int availablePermits()
// 獲取並返回立即可用的所有許可。
int drainPermits()
// 返回一個 collection,包含可能等待獲取的線程。
protected Collection<Thread> getQueuedThreads()
// 返回正在等待獲取的線程的估計數目。
int getQueueLength()
// 查詢是否有線程正在等待獲取。
boolean hasQueuedThreads()
// 如果此信號量的公平設置爲 true,則返回 true。
boolean isFair()
// 根據指定的縮減量減小可用許可的數目。
protected void reducePermits(int reduction)
// 釋放一個許可,將其返回給信號量。在釋放許可之前,必須先獲獲得許可
void release()
// 釋放給定數目的許可,將其返回到信號量。
void release(int permits)
// 返回標識此信號量的字符串,以及信號量的狀態。
String toString()
// 嘗試獲取一個許可,若獲取成功返回true,若獲取失敗返回false, 僅在調用時此信號量存在一個可用許可,才從信號量獲取許可。
boolean tryAcquire()
// 僅在調用時此信號量中有給定數目的許可時,才從此信號量中獲取這些許可。
boolean tryAcquire(int permits)
// 如果在給定的等待時間內此信號量有可用的所有許可,並且當前線程未被中斷,則從此信號量獲取給定數目的許可。
boolean tryAcquire(int permits, long timeout, TimeUnit unit)
// 如果在給定的等待時間內,此信號量有可用的許可並且當前線程未被中斷,則從此信號量獲取一個許可。
boolean tryAcquire(long timeout, TimeUnit unit)

上面是基本常見的方法,Semaphore底層是由AQS和Uasafe完成的,調用的是

protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

步驟

  1. 初始化
  2. 增加
  3. 減少

示例

public class SemaphoreDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();

        //信號量,只允許 3個線程同時訪問
        final Semaphore semaphore = new Semaphore(3);

        for (int i=0;i<10;i++){
            final long num = i;
            executorService.submit(new Runnable() {
                public void run() {
                    try {
                        //獲取許可
                        semaphore.acquire();
                        //執行
                        System.out.println("執行: " + num);
                        Thread.sleep(new Random().nextInt(5000)); // 模擬隨機執行時長
                        //釋放
                        semaphore.release();
                        System.out.println("釋放..." + num);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        executorService.shutdown();
    }
}

總結

​ Semaphore主要用於控制當前活動線程數目,就如同停車場系統一般,而Semaphore則相當於看守的人,用於控制總共允許停車的停車位的個數,而對於每輛車來說就如同一個線程,線程需要通過acquire()方法獲取許可,而release()釋放許可。如果許可數達到最大活動數,那麼調用acquire()之後,便進入等待隊列,等待已獲得許可的線程釋放許可,從而使得多線程能夠合理的運行。

如果大家對java架構相關感興趣,可以關注下面公衆號,會持續更新java基礎面試題, netty, spring boot,spring cloud等系列文章,一系列乾貨隨時送達, 超神之路從此展開, BTAJ不再是夢想!

架構殿堂

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章