其思路: 使用訊號量 semaphore 有加有減,控制併發。
圖出自上方鏈結。
我不理解,兩個都是semapore(1);不可以麼?即使不能確定哪個執行緒先執行,使兩個執行緒交替執行應該是ok的吧。
此時,我對semaphore的使用還非常不熟悉。
那麼驗證一下我的猜想。
實現效果:列印1-100的數值,兩個執行緒a b,a執行緒列印奇數,b執行緒列印偶數。
public執行結果:顯然不太對,orz。以下只是一種執行結果,實際上有可能是b執行緒先執行。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) }}
}
執行緒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使用:也就是 semaphore(0) 的時候,並不是不可以acquire();,只要release();一次那就可以acquire();一次。* 假設release()n次,就能直接acquire() (n + permits)次!
* permits也可以為負數,沒有限制。當(n+permits)> 0 時,acquire();才會成功。
* eg: new semaphore(-1); 當 連續release 2次之後,就能acquire();成功 1次。
** 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執行結果:執行緒a與b交替列印,程式正常關閉。class
semaphoretest_2
}
。。。執行緒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執行緒先執行。其實整個思路就是利用了semaphore(0);的單向執行,semaphore(-1,-2)其實都擁有這個特性,也能實現相應的功能,只是可以但沒必要。* 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();時成功,繼續執行第二個迴圈的邏輯
* 以此類推
具體做法就是修改一下兩處**:
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 有時被稱為訊號燈,是在多執行緒環境下使用的一種設施,是可以用來保證兩個或多個關鍵 段不被併發呼叫。在進入乙個關鍵 段之前,執行緒必須獲取乙個訊號量 一旦該關鍵 段完成了,那麼該執行緒必須釋放訊號量。其它想進入該關鍵 段的執行緒必須等待直到第乙個執行緒釋放訊號量。為了完成這...