信號量的實現模型一般包括:1個計數器、1個等待隊列、3個方法(需要保證原子性)
Semaphore 實現的偽代碼(JDK 中 Semaphore 是基於 AbstractQueuedSynchronizer 實現,可以指定是否公平):
class Semaphore{ //計數器 int count; //等待隊列 Queue queue; //初始化 Semaphore(int c){ this.count=c; } //獲取許可證 void acquire(){ count--; if(count<0){ //將當前線程插入等待隊列 //阻塞當前線程 } } //獲取許可證 void release(){ count++; if(count<=0) { //移除等待隊列中的某個線程 //喚醒某個線程 } } }
使用信號量實現互斥鎖效果:
package constxiong.interview; import java.util.concurrent.Semaphore; /** * 測試使用信號量實現鎖的效果 * @author ConstXiong * @date 2019-12-18 14:18:47 */ public class TestSemaphore { private static int count; private static Semaphore semaphore = new Semaphore(1); public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread(() -> { add(); System.out.println(count); }).start(); } } private static void add() { try { semaphore.acquire(); Thread.sleep(100); count++; } catch(InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } } }
除了能實現互斥鎖,信號量還可以做到允許多個線程訪問同一個臨界區,這是它與互斥鎖一個較大的區別點。
將代碼進行修改,實現限流功能:
package constxiong.interview; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; /** * 測試使用信號量實現限流的效果 * @author ConstXiong * @date 2019-12-18 14:18:47 */ public class TestSemaphore { private static AtomicInteger acount = new AtomicInteger(0); private static Semaphore semaphore = new Semaphore(10); public static void main(String[] args) { testAddAtomic(); } /** * 測試允許十個線程並發遞增 acount */ private static void testAddAtomic() { for (int i = 0; i < 100; i++) { new Thread(() -> { System.out.println(addAtomic()); }).start(); } } private static int addAtomic() { try { semaphore.acquire(); Thread.sleep(100); return acount.incrementAndGet(); } catch(InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } return -1; } }
在實際的 Java 開發中,信號量的使用相對互斥鎖來說較少,知名度沒那么高,但在其他編程語言中使用較廣。
- Java 自學指南
- Java 面試題匯總PC端瀏覽【點這里】
- Java知識圖譜
- Java 面試題匯總小程序瀏覽,掃二維碼