併發工具 Semaphore

定義

Semaphore :信號量,併發控制中用於控制某個資源同時被訪問的個數。例如程序中某個方法執行耗時長,所需資源量大。可以通過Semaphore控制同一時刻訪問該方法的線程數。

應用場景

主要用於流量控制,特別是公共資源有限的的應用場景(數據庫連接)或者一些慢服務

主要方法

  1. public Semaphore(int permits) :構造函數一,permits爲信號量許可證的大小;
  2. public Semaphore(int permits, boolean fair) :構造函數二:fair爲是否設置公平策略參數,如果爲true,申請許可證的等待線程會進入FIFO隊列中。若爲false,允許等待的線程有插隊的可能。
  3. public void acquire():以阻塞的方式獲取一個申請許可證,在有可用的許可證時候就返回許可;如果沒有可用的許可則阻塞等待,直至獲取到許可;
  4. public void acquire(int permits):同時獲取permits個許可;
  5. public void release():釋放一個許可;
  6. public void acquire(int permits):釋放permits個許可;
  7. public boolean tryAcquire():嘗試獲取許可證,如果當前沒有可用的許可證,申請的線程不需要進入阻塞,而是繼續往下執行;
  8. public boolean tryAcquire(long timeout, TimeUnit unit) :帶有超時時間去獲取蓄許可證。例如“5秒鐘內還是獲取不到許可證,我就繼續往下執行,幹自己的事!”
  9. public int availablePermits():查詢可用的許可;

例子


package com.mark.learning.concurrent2.flowcontrol.semaphore;

import lombok.extern.slf4j.Slf4j;

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

/**
 * @Description: 演示Semaphore用法
 * @Author: Mark
 * @CreateDate: 2020/2/3 14:15
 * @Version: 1.0
 * @Copyright : 豆漿油條個人非正式工作室
 */
@Slf4j
class Task implements Runnable{

    private static final Semaphore SEMAPHORE = new Semaphore(3,true);

    @Override
    public void run() {
        //獲取信號量許可證
        try {
            SEMAPHORE.acquire();
            log.info(Thread.currentThread().getName()+"獲取到了 信號量許可證");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //模擬 耗時長的程序
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //釋放信號量
        SEMAPHORE.release();
        log.info(Thread.currentThread().getName()+"釋放了 信號量許可證");
    }
}

public class SemaphoreDemo1 {
    private static ExecutorService executorService = Executors.newFixedThreadPool(5);

    public static void main(String[] args) {
        //運行十個線程
        for (int i = 0; i < 10; i++) {
            executorService.execute(new Task());
        }
        executorService.shutdown();
    }
}

運行結果

16:39:57.795 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1獲取到了 信號量許可證
16:39:57.795 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2獲取到了 信號量許可證
16:39:57.795 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5獲取到了 信號量許可證
16:40:02.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1釋放了 信號量許可證
16:40:02.801 [pool-1-thread-3] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-3獲取到了 信號量許可證
16:40:02.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4獲取到了 信號量許可證
16:40:02.801 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5釋放了 信號量許可證
16:40:02.801 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2釋放了 信號量許可證
16:40:02.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1獲取到了 信號量許可證
16:40:07.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4釋放了 信號量許可證
16:40:07.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1釋放了 信號量許可證
16:40:07.801 [pool-1-thread-3] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-3釋放了 信號量許可證
16:40:07.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4獲取到了 信號量許可證
16:40:07.801 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5獲取到了 信號量許可證
16:40:07.801 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2獲取到了 信號量許可證
16:40:12.802 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2釋放了 信號量許可證
16:40:12.802 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1獲取到了 信號量許可證
16:40:12.802 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5釋放了 信號量許可證
16:40:12.802 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4釋放了 信號量許可證
16:40:17.803 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1釋放了 信號量許可證

通過分析log的打印時間,每次最多隻能允許3個線程同時執行。

注意點

  • 一次獲取可獲取和釋放多個許可證。
 semaphore.acquire(3);//一次獲取三個許可
 semaphore.release(3);//一次釋放三個許可
  • 獲取許可和釋放許可的數量需要保持一致;
  • 釋放許可不一定由獲取的許可來完成。例如線程A獲取了許可,也可以由線程B來釋放許可
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章