天天看點

Semaphore信号量

# Semaphore信号量

Semaphore信号量

  • Semaphore 可以用來限制或管理數量有限資源的使用情況
  • 信号量的作用是用來維護一個“許可證”,的計數,線程可以擷取 許可證,那信号量剩餘許可證就減一,線程也可以是否一個許可證,那剩餘的許可證就加一,當信号量擁有的許可證為0時,那麼下一個線程想獲得許可證,就要進行等待,直到另外線程釋放許可證

信号量使用流程

: 1.初始化Semaphore 并指定許可證的數量

: 2.在需要被現在的代碼前加acquire() 或者 acquireUninterruptibly()方法

: 3.在任務結束後,調用release() 來釋放許可證

信号量主要方法使用

: 1.new Semaphore(int permits,boolean fair): 這裡可以設定是否使用公平政策,如果傳入true,那麼Semaphore 會把之前等待的線程放到FIFO的隊列裡,以便于當有了新的許可證,可以分發給之前等了最長時間的線程

: 2.tryAcquire() : 看看現在有沒有空閑的許可證,如果有的話就擷取,如果沒有的話也沒關系,我不必陷入阻塞,我可以i去做别的事情,過一會再來檢視許可證的空閑情況

: 3.tryAcquire(timeout) : 和tryAcquire()一樣,但是多了逾時時間,比如 “在3秒内擷取不到許可證,我去做别的事情”

  • 代碼示範
package com.yxl.task;


import lombok.SneakyThrows;
import org.omg.PortableInterceptor.INACTIVE;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.*;

/**
 * Semaphore 示範demo
 */
public class SemaphoreDemo {

     static Semaphore semaphore =new Semaphore(3,true);
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(50);
        for (int i = 0; i < 50; i++) {
            executorService.execute(new Task());
        }
        executorService.shutdown();

    }
    static class Task implements Runnable{
        @SneakyThrows
        @Override
        public void run() {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName()+"拿到來許可證");
            Thread.sleep(200);
            System.out.println(Thread.currentThread().getName()+"釋放了許可證");
            semaphore.release();
        }
    }
}
           
Semaphore信号量

運作結果,會發現他是3個那到,三個釋放 執行線程

我們修改擷取信号量到參數

@SneakyThrows
        @Override
        public void run() {
            semaphore.acquire(3);
            System.out.println(Thread.currentThread().getName()+"拿到來許可證");
            Thread.sleep(200);
            System.out.println(Thread.currentThread().getName()+"釋放了許可證");
            semaphore.release(3);
        }           

每次運作一個線程都會拿到3個許可證

Semaphore信号量
  • 可以根據我們到需求一次擷取或者釋放多個許可證
  • 比如TaskA會調用很消耗資源到 method1() 而TaskB 調用到是不太消耗資源到 mehod2(), 假設我們一共有5個許可證,那麼我們就可以要求TaskA 擷取5個許可證才能執行,這樣避免了A B 同時運作到情況,我們可以根據直接到需求和裡配置設定資源

注意點

: 1.擷取和釋放到許可證數量必須一緻,否則比如每次都擷取2個但是隻釋放一個甚至不釋放,随着時間到推移,到最後許可證數量不夠用,會導緻程式卡死。

: 2.注意在初始化Semaphore的時候設定公平性,一般設定為 true 更合理

: 3.信号量的作用,除了控制臨界區最多同時有N個線程通路外,林一個作用是可以實作“條件等待”,例如 線程1需要線上程2完成準備工作後才能開始工作,那麼線程1 acquire() , 而線程2完成任務後release(),這樣電話,相當于輕量級的CountDownLatch

個人部落格位址:

http://blog.yanxiaolong.cn/