高併發(10)- 線程併發工具類-Semaphore

前言

上篇文章講解了線程的併發工具類之CyclicBarrier,本文就來講解Semaphore併發工具類
CyclicBarrier其實就是一個柵欄,需要等所有線程都到達柵欄纔可以繼續執行。
Semaphore則是類似於信號量,有一個固定數量的憑證,線程來了拿走一個,用完還回來,當沒有憑證可使用的時候,就開始等待

什麼是Semaphore

Semaphore就是一個信號量。必須是獲取他的線程釋放,通常用來現在某些資源訪問數量的場景使用。

Semaphore執行圖

如上圖所示,Semaphore定義了4個,當有線程進來時,需要通過acquire()方法取走一個憑證,當用完時,在通過release()方法將憑證返回。而當有多個線程湧進時,只有四個線程取到了憑證,其他的線程就需要等待其他線程release()返回憑證,然後執行。

就如同生活中,去飯店喫飯,只有四張桌子,所以同時只允許四波客人喫飯,如果同時來了五批客人,服務員會讓四批客人就做(獲取憑證),第五批客人則是等待,因爲這時候沒有座位了,也就是沒有憑證了,需要等有桌客人離坐(釋放憑證),然後招呼第五批客人入座(獲取憑證)。

一個信號量有且僅有 3 種操作,且它們全部是原子的。
初始化、增加和減少。
增加可以爲一個進程解除阻塞。
減少可以讓一個進程進入阻塞。

Semaphore有什麼用

Semaphore有兩個目的,第一個目的是多個共享資源互斥使用,第二目的是併發線程數的控制

1.共享資源互斥使用

例如我給我個共享資源加上了Semaphore等於1,所以肯定只有一個線程可以來使用這個資源,這就達到了共享資源互斥使用,

2.併發線程數的控制

比如我們有個線程池,需要限定併發線程的數量,我們就可以使用Semaphore來指定併發數量,所有的線程進來時都要獲取憑證,取不到則等待,這就達到了併發線程數的控制效果。

Semaphore的實現

構造方法

//創建指定長度的信號量,不公平的,
public Semaphore(int permits);
//創建指定長度的信號量,fair爲true則是公平的
public Semaphore(int permits,boolean fair);

所謂的公平信號量是獲得鎖的順序與調用semaphore.acquire()的順序有關,但不代表100%地獲得信號量,僅僅是在概率上能得到保證。而非公平信號量就是無關的了。

Semaphore(int permits)構造方法是創建指定數量的信號量,屬於不公平的信號量。

Semaphore(int permits,boolean fair);構造方法是創建指定數量的信號量,fair爲true則是公平的信號量,否則相反。

普通方法

//獲取一個平成
public void acquire();
//獲取指定數量的憑證,在提供這些憑證前一直將線程阻塞。比如n=2,就相當於佔用了兩個憑證
public void acquire(int n);
//釋放一個憑證
public void release();
//釋放n個憑證
public void release(int n);
//當前可用的憑證數
public int availablePermits();;

代碼實現

/**
 * @version 1.0
 * @Description SemaphoreDemo
 * @Author wb.yang
 * @Date 2020/4/3 7:21
 */
public class SemaphoreDemo {

	/**
	 * 創建指定長度信號量
	 */
	private static final Semaphore SEMAPHORE = new Semaphore(2);


	/**
	 * 工作線程
	 */
	public static class SubThread implements Runnable {

		@Override
		public void run() {
			long id = Thread.currentThread().getId();
			try {
				System.out.println("Thread_" + id + "準備開始獲取憑證");
				SEMAPHORE.acquire();
				System.out.println("Thread_" + id + "獲取到憑證執行輸出,剩餘憑證:" + SEMAPHORE.availablePermits());
				Thread.sleep(1000);
				System.out.println("Thread_" + id + "準備開始返回憑證");
				SEMAPHORE.release();
				System.out.println("Thread_" + id + "返回憑證輸出,剩餘憑證:" + SEMAPHORE.availablePermits());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i <= 3; i++) {
			Thread thread = new Thread(new SubThread());
			thread.start();
		}
	}

}

從代碼中看出,我們定義了兩個信號量,然後我們有一個工作線程。先獲取了憑證,然後在執行業務邏輯,最後返回憑證,打印憑證數量。然後啓動了四個線程,來測試這個代碼。
代碼返回結果
從代碼結果可以看出,四個線程開始準備獲取憑證,然後然後兩個線程獲取到了憑證,並且輸出了剩餘的憑證。然後剩下兩個線程就在等待憑證,當哪兩個線程執行完,釋放了憑證,剩下的線程再去去獲取憑證,然後執行之後的業務。

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