訊號量Semaphore實現兩個執行緒的交替執行

2022-09-14 14:06:26 字數 3146 閱讀 1197

其思路:    使用訊號量 semaphore 有加有減,控制併發。

圖出自上方鏈結。

我不理解,兩個都是semapore(1);不可以麼?即使不能確定哪個執行緒先執行,使兩個執行緒交替執行應該是ok的吧。

此時,我對semaphore的使用還非常不熟悉。

那麼驗證一下我的猜想。

實現效果:列印1-100的數值,兩個執行緒a b,a執行緒列印奇數,b執行緒列印偶數。

public

class

semaphoretest_2

}class a_th_semp_2 extends

thread

@override

public

void

run()

catch

(interruptedexception e) }}

}class b_th_semp_2 extends

thread

@override

public

void

run()

catch

(interruptedexception e) }}

}

執行結果:顯然不太對,orz。以下只是一種執行結果,實際上有可能是b執行緒先執行。

執行緒a:==>1

執行緒b:==>2

執行緒a:==>3

執行緒b:==>4

執行緒b:==>6

執行緒a:==>5

執行緒b:==>8

執行緒a:==>7

執行緒a:==>9

執行緒b:==>10

執行緒a:==>11

執行緒b:==>12

執行緒b:==>14 。。。

分析原因:

*  * 失敗原因在於:

* b執行緒乙個迴圈結束即s1 release()之後,進入下乙個迴圈時s0.acquire()有可能直接獲取到。

** 假設a執行緒先獲取s1後列印a完成,進入sleep();此時 b執行緒獲取了s0列印b完成 進入sleep();

* 執行緒a sleep()完成之後釋放s0,進入下乙個迴圈獲取s1失敗(此時b 執行緒還是sleep,沒有釋放s1),在此處阻塞

* 執行緒b sleep()完成之後釋放s1,進入下乙個迴圈獲取s0成功(s0由執行緒a 釋放),直接列印b;後進入sleep();

* 執行緒a 一直在獲取s1,此時獲取s1成功,列印 a成功後進入sleep();

* 因此出現了連續列印兩個b ,連續列印兩個a的情況。

*    訊號量semaphore使用:

* 假設release()n次,就能直接acquire() (n + permits)次!

* permits也可以為負數,沒有限制。當(n+permits)> 0 時,acquire();才會成功。

* eg: new semaphore(-1); 當 連續release 2次之後,就能acquire();成功 1次。

** release()並不會 阻塞執行緒,只有acquire() 會阻塞執行緒

也就是 semaphore(0) 的時候,並不是不可以acquire();,只要release();一次那就可以acquire();一次。

acquire(int n); 其實可以有引數獲取n個,其效果相當於連續執行了n次acquire();release(int n);同理。

某種程度上semaphore也是可以迴圈使用的,只要release() 之後就可以重新 acquire()。而countdownlatch是真正意義上的無法迴圈使用。

semaphore(0,-1) 類似於單向執行 ,只有在release();執行n次,(n+permits) > 0之後 才能acquire();成功。

那麼要實現交替列印的功能,只要修改呼叫**為:

public

class

semaphoretest_2

}

執行結果:執行緒a與b交替列印,程式正常關閉。

。。。執行緒a:==>87

執行緒b:==>88

執行緒a:==>89

執行緒b:==>90

執行緒a:==>91

執行緒b:==>92

執行緒a:==>93

執行緒b:==>94

執行緒a:==>95

執行緒b:==>96

執行緒a:==>97

執行緒b:==>98

執行緒a:==>99

執行緒b:==>100

**執行流程是:

* 由於s0的permits為0,所以一定是a執行緒先執行。

* a執行緒 s1.acquire();成功後執行列印等操作,進入sleep();此時 b執行緒 s0 依舊acquire();失敗

* 當 a執行緒 休眠完畢,s0.release(); 直接進入下一迴圈,s1.acquire();時阻塞(由於上個迴圈acquire();之後並沒有release();所以再次 .acquire();時阻塞 )

* 此時 b執行緒 s0.acquire();成功 (a執行緒 上個迴圈釋放了s0),執行列印等操作之後,進入sleep;此時 a執行緒s1.acquire(); 依舊失敗,理由同上;

* 當 b執行緒 休眠完畢,s1.release();直接進入下一迴圈,s0.acquire();時阻塞。(由於a 執行緒上個迴圈的release();被b 執行緒的上個迴圈使用了,需等待下乙個relase;)

* 此時 a執行緒 s1.acquire();時成功,繼續執行第二個迴圈的邏輯

* 以此類推

其實整個思路就是利用了semaphore(0);的單向執行,semaphore(-1,-2)其實都擁有這個特性,也能實現相應的功能,只是可以但沒必要。

具體做法就是修改一下兩處**:

main(***);中初始化時s0改為-1;a執行緒中 s0.release();改為s0.release(2);

semaphore s0 = new semaphore(-1);
s0.release(2);
執行效果自行驗證。

訊號量semaphore解析

1 基礎概念 訊號量在建立時須要設定乙個初始值,表示同一時候能夠有幾個任務能夠訪問該訊號量保護的共享資源。初始值為1就變成相互排斥鎖 mutex 即同一時候僅僅能有乙個任務能夠訪問訊號量保護的共享資源。乙個任務要想訪問共享資源,首先必須得到訊號量,獲取訊號量的操作將把訊號量的值減1。若當前訊號量的值...

Semaphore初識 java訊號量

朋友在寫 活動的時候,為了控制線程,用到了semaphore類 之前也是沒有用到過,就簡單認識一下它。semaphore,是負責協調各個執行緒,以保證它們能夠正確 合理的使用公共資源。也是作業系統中用於控制程序同步互斥的量。或者說,簡單的來講,就 是訊號量。比如我們去網咖開機子上網 原諒樓主是個網癮...

訊號量Semaphore學習總結

訊號量 semaphore 有時被稱為訊號燈,是在多執行緒環境下使用的一種設施,是可以用來保證兩個或多個關鍵 段不被併發呼叫。在進入乙個關鍵 段之前,執行緒必須獲取乙個訊號量 一旦該關鍵 段完成了,那麼該執行緒必須釋放訊號量。其它想進入該關鍵 段的執行緒必須等待直到第乙個執行緒釋放訊號量。為了完成這...