鎖之鎖的三種狀態及Monitor.Wait, Monitor.Pulse,Monitor.PulseAll的作用與用法
目錄
1.線程鎖的三種狀態
2.Monitor.Wait,Monitor.Pulse的作用
3.Monitor.PulseAll的作用
4.總結(Q&A)
1.線程鎖的三種狀態
首先我們記住有有鎖線程的三種狀態:[持有鎖的線程],[就緒隊列],[等待隊列]
微軟官方文檔中英文截圖釋義如下[2][3]:
整理後中英文及釋義對照表如下:
中文 |
英文 |
釋義 |
[等待隊列] |
waiting queue |
線程運行到Wait處後狀態被改爲的等待隊列,需要進入就緒隊列纔拿到鎖 |
[就緒隊列] |
ready queue |
即將進入執行中的帶鎖的線程 |
[持有鎖的線程] |
the thread that |
執行中的帶鎖的線程 |
軟件中運行優先順序爲:
1.先運行 [持有鎖的線程] ,
2.然後是 [就緒隊列] 中排在最前的線程。
3.只有[等待隊列] 的線程進入[就緒隊列]纔有排隊資格,且排到最前纔會進入[持有鎖的線程]
需要注意:
1. 當前只能有一個線程狀態爲[持有鎖的線程]
2. 前一個線程釋放了鎖,纔可排到[就緒隊列]中最前的線程
3. 若[等待隊列]一直進入不了[就緒隊列]則一直不計入排隊序列
以超市購物爲例,
同個結賬窗口中:
1.當前窗口只能有一個客戶在結賬
2.只有前一個客戶結完賬後,排隊隊伍中排到最前的客戶纔可結賬
3.超市裏面排隊採購,排隊結賬,若不排隊則不能結賬
若結賬窗口是鎖,則:
1. [持有鎖的線程] 即 當前窗口結帳中的顧客(結賬中)
2. [就緒隊列] 即 排隊準備結賬的顧客們(排隊中)
3. [等待隊列] 即 仍在超市採購的顧客們(有順序的採購中)
2.Monitor.Wait,Monitor.Pulse的作用
前文已說過有鎖線程的三種狀態:[持有鎖的線程],[就緒隊列],[等待隊列]
軟件中運行優先順序爲:
1.先運行 [持有鎖的線程] ,
2.然後是 [就緒隊列] 中排在最前的線程。
3.只有[等待隊列] 的線程進入[就緒隊列]纔有排隊資格,且排到最前纔會進入[持有鎖的線程]
以上記好
那麼Monitor.Wait和Monitor.Pulse是什麼意思呢?
Visual Studio中直接按F12或右鍵->轉到定義,我們發現官方解釋是如下
其中Monitor.Pulse的解釋爲:
//摘要: 通知等待隊列中的線程鎖定對象狀態的更改。
//Summary:Notifies a thread in the waiting queue of a change in the locked object's state.
Monitor.Wait中英文釋義如下:
//摘要: 釋放對象上的鎖並阻止當前線程,直到它重新獲取該鎖。如果指定的超時間隔已過,則線程進入就緒隊列。
//Summary:Releases the lock on an object and blocks the current thread until it reacquires the lock.
不知道你們看懂沒,我看上面的摘要的中文看的雲裏霧裏的,英文看的迷迷糊糊的,
按F12或右鍵->轉到定義 相關截圖如下:
Monitor.Pulse解釋如下:
然後查好久查到如下微軟官方文檔[2][3]:
從微軟官方文檔中總結出:
Wait 作用是:將[持有鎖的線程]的本線程狀態改爲[等待隊列]
Pulse作用是:將排在[等待隊列] 最前的線程 移到[就緒隊列]
前面我們舉過例子:
1. [持有鎖的線程] 即(結賬中)
2. [就緒隊列] 即(排隊中)
3. [等待隊列] 即(有順序的採購中)
然後
Wait 作用是:將當前結賬的顧客拉回到超市裏面瞎逛,
即當前狀態從(結賬中)轉爲(有順序的採購中)。
Pulse作用是:將在超市裏瞎逛的顧客拉去排隊,
即當前狀態從排在最前的(有順序的採購中)狀態轉爲(排隊中)。
微軟官網沒明說,那就說明Pulse後轉到[就緒隊列]的線程很可能會插隊。
那麼又有新的疑問:
<問1>若有多個wait同時起作用,那麼多個線程狀態在[等待隊列]中的排序是?
<問2> 單個Pulse作用是將[等待隊列] 最前的線程 移到[就緒隊列]的第幾位?
上面兩個問題微軟官網查了好久,沒查到
我們來寫個測試程序測試下:
開6個線程其中[線程A]和[線程B]中有Wait,[線程C]中有Pulse,通過控制Thread.Sleep來控制線程到達[就緒隊列]的順序爲A, B,C,D,E,F。
部分代碼如下:
private void button7_Click(object sender, EventArgs e)
{
this.Hide();
Console.WriteLine("[主線程] " + DateTime.Now.ToString() + "開啓子線程");
Thread aa = new Thread(A); aa.IsBackground = true; aa.Name = "[線程A]"; aa.Start();
Thread bb = new Thread(B); bb.IsBackground = true; bb.Name = "[線程B]"; bb.Start();
Thread cc = new Thread(C); cc.IsBackground = true; cc.Name = "[線程C]"; cc.Start();
Thread dd = new Thread(D); dd.IsBackground = true; dd.Name = "[線程D]"; dd.Start();
Thread ee = new Thread(E); ee.IsBackground = true; ee.Name = "[線程E]"; ee.Start();
Thread ff = new Thread(F); ff.IsBackground = true; ff.Name = "[線程F]"; ff.Start();
Console.ReadLine();
}
private static object objLockTest = new object();
private static void A()
{
Console.WriteLine("[線程A] 開啓...");
Thread.Sleep(100);
Console.WriteLine("[線程A] [就緒隊列]");
lock (objLockTest) //進入[就緒隊列]隊列
{
Console.WriteLine("[線程A] [持有鎖的線程]");
Thread.Sleep(1000);
Console.WriteLine("[線程A] Monitor.Pulse," + DateTime.Now.ToString("HH:mm:ss:fff"));
//Notifies a thread in the waiting queue of a change in the locked object's state.
Monitor.Pulse(objLockTest);
Thread.Sleep(100);
Console.WriteLine("[線程A] Monitor.Wait ," + DateTime.Now.ToString("HH:mm:ss:fff"));
//Releases the lock on an object and blocks the current thread until it reacquires the lock.
//(Monitor.Wait將本線程添加到[等待隊列]
//超時時間:線程進入就緒隊列之前等待的毫秒數,即從Wait 到Pulse之間的毫秒數,
// 若無超時時間,且無Pulse喚醒,則本線程一直會處於[等待隊列]
if (Monitor.Wait(objLockTest, 3000))
Console.WriteLine("[線程A] 重新獲得該鎖(在指定的時間過期之前)" + DateTime.Now.ToString("HH:mm:ss:fff"));
else
Console.WriteLine("[線程A] 重新獲得該鎖(在指定的時間過期之後)" + DateTime.Now.ToString("HH:mm:ss:fff"));
Thread.Sleep(4000);
Console.WriteLine("[線程A] 退出..." + DateTime.Now.ToString("HH:mm:ss:fff"));
}
}
private static void B()
{
Console.WriteLine("[線程B] 開啓...");
Thread.Sleep(150);
Console.WriteLine("[線程B] [就緒隊列]");
lock (objLockTest)
{
Console.WriteLine("[線程B] [持有鎖的線程]");
Thread.Sleep(100);
Console.WriteLine("[線程B] Monitor.Wait," + DateTime.Now.ToString("HH:mm:ss:fff"));
if (Monitor.Wait(objLockTest, 3000))
Console.WriteLine("[線程B] 重新獲得該鎖(在指定的時間過期之前)" + DateTime.Now.ToString("HH:mm:ss:fff"));
else
Console.WriteLine("[線程B] 重新獲得該鎖(在指定的時間過期之後)" + DateTime.Now.ToString("HH:mm:ss:fff"));
Thread.Sleep(500);
Console.WriteLine("[線程B] 退出...");
}
}
private static void C()
{
Console.WriteLine("[線程C] 開啓...");
Thread.Sleep(200);
Console.WriteLine("[線程C] [就緒隊列]");
lock (objLockTest)
{
Console.WriteLine("[線程C] [持有鎖的線程]");
Thread.Sleep(100);
Console.WriteLine("[線程C] Monitor.Pulse," + DateTime.Now.ToString("HH:mm:ss:fff"));
//Notifies a thread in the waiting queue of a change in the locked object's state.
Monitor.Pulse(objLockTest);
Thread.Sleep(500);
Console.WriteLine("[線程C] 退出...");
}
}
private static void D()
{
Console.WriteLine("[線程D] 開啓...");
Thread.Sleep(250);
Console.WriteLine("[線程D] [就緒隊列]");
lock (objLockTest)
{
Console.WriteLine("[線程D] [持有鎖的線程]");
Thread.Sleep(500);
Console.WriteLine("[線程D] 退出...");
}
}
private static void E()
{
Console.WriteLine("[線程E] 開啓...");
Thread.Sleep(300);
Console.WriteLine("[線程E] [就緒隊列]");
lock (objLockTest)
{
Console.WriteLine("[線程E] [持有鎖的線程]" + DateTime.Now.ToString("HH:mm:ss:fff"));
Thread.Sleep(500);
Console.WriteLine("[線程E] 退出...");
}
}
private static void F()
{
Console.WriteLine("[線程F] 開啓...");
Thread.Sleep(350);
Console.WriteLine("[線程F] [就緒隊列]");
lock (objLockTest)
{
Console.WriteLine("[線程F] [持有鎖的線程]" + DateTime.Now.ToString("HH:mm:ss:fff"));
Thread.Sleep(500);
Console.WriteLine("[線程F] 退出...");
}
}
軟件運行結果及對應釋義圖如下:
上圖中綠色畫線處爲Wait ,Pulse使用後的結果的釋義。
我們設置線程到達[就緒隊列]狀態的順序爲:A-> B->C->D->E->F。
[線程A]中有代碼if (Monitor.Wait(objLockTest, 3000))
[線程B]中有代碼if (Monitor.Wait(objLockTest, 3000))
[線程C]中有代碼Monitor.Pulse(objLockTest);
則線程狀態變爲[持有鎖的線程] 順序爲:A(Pulse,Wait)->B(Wait)->C(Pulse)->D->A->E->F
從剛程序中線程[持有鎖的線程] 順序的狀態變化我們得出瞭如下結論:
結論1. 線程中若最先運行的Pulse,則此Pulse無作用。
結論2. 當前運行的線程Wait後會釋放本線程的鎖並將本線程移到[等待隊列]
結論3. 無論當前運行的線程是否調用Pulse,下一個都會運行到原來就排在[就緒隊列]首位的線程。
結論4. 線程Pulse後將[等待隊列] 最前的線程 移到[就緒隊列], 即默認將第一個調用Wait的線程移動到[就緒隊列]
結論5. Wait的超時時間統計的是[等待隊列]到[就緒隊列]所用的時間,即調用Wait的時間與Pulse的時間差,若時間差小於超時時間,則返回True,反之,返回False。
結論6.單個Pulse運行將 [等待隊列] 最前的線程 大概率插隊到[就緒隊列]的第二位(此結論是從結論3基礎上以邏輯方式推理出來的)
那麼以上兩個問題,我們都有了解釋
<問1>若有多個wait同時起作用,那麼多個線程狀態在[等待隊列]中的排序是?
<答1>多個wait起作用後多個線程依次進入[等待隊列]狀態,即最先進入[等待隊列]的排在最前。
<問2> 單個Pulse作用是將[等待隊列] 最前的線程 移到[就緒隊列]的第幾位?
<答2>單個Pulse運行後從本程序上看,應該是[等待隊列] 最前的線程 大概率插隊到[就緒隊列]的第二位。
以上結論與微軟官方文檔釋義相同,
官方文檔截圖如下[4][5]:
附贈軟件運行順序及運行後各個線程的狀態圖表:
|
[持有鎖的線程] |
[就緒隊列] |
[等待隊列] |
[主線程] 2020/4/13 13:32:03開啓子線程 |
|
|
|
[線程C] 開啓... |
|
|
|
[線程A] 開啓... |
|
|
|
[線程D] 開啓... |
|
|
|
[線程E] 開啓... |
|
|
|
[線程B] 開啓... |
|
|
|
[線程F] 開啓... |
|
|
|
[線程A] [就緒隊列] |
|
A |
|
[線程A] [持有鎖的線程] |
A |
|
|
[線程B] [就緒隊列] |
A |
B |
|
[線程C] [就緒隊列] |
A |
B,C |
|
[線程D] [就緒隊列] |
A |
B,C,D |
|
[線程E] [就緒隊列] |
A |
B,C,D,E |
|
[線程F] [就緒隊列] |
A |
B,C,D,E,F |
|
[線程A] Monitor.Pulse,13:32:04:161 |
A |
B,C,D,E,F |
|
[線程A] Monitor.Wait ,13:32:04:271 |
|
B,C,D,E,F |
A |
[線程B] [持有鎖的線程] |
B |
C,D,E,F |
A |
[線程B] Monitor.Wait,13:32:04:380 |
|
C,D,E,F |
A,B |
[線程C] [持有鎖的線程] |
C |
D,E,F |
A,B |
[線程C] Monitor.Pulse,13:32:04:489 |
C |
D,A,E,F |
B |
[線程C] 退出... |
|
D,A,E,F |
B |
[線程D] [持有鎖的線程] |
D |
A,E,F |
B |
[線程D] 退出... |
|
A,E,F |
B |
[線程A] 重新獲得該鎖(在指定的時間過期之前)13:32:05:520 |
A |
E,F |
B |
軟件的[線程B]中Wait超時時間3000ms |
A |
E,B,F |
|
[線程A] 退出...13:32:09:535 |
|
E,B,F |
|
[線程E] [持有鎖的線程]13:32:09:535 |
E |
B,F |
|
[線程E] 退出... |
|
B,F |
|
[線程B] 重新獲得該鎖(在指定的時間過期之後)13:32:10:051 |
B |
F |
|
[線程B] 退出... |
|
F |
|
[線程F] [持有鎖的線程]13:32:10:566 |
F |
|
|
[線程F] 退出... |
|
|
|
3.Monitor.PulseAll的作用
<問 6>請問Monitor.PulseAll具體的作用是?
多說無益代碼驗證如下
改爲先開啓線程C,即先運行cc.Start();
[線程A]中if (Monitor.Wait(objLockTest, 300))
[線程B]中if (Monitor.Wait(objLockTest, 3000))
[線程C]中if (Monitor.Wait(objLockTest, 3000))
[線程D]中Monitor.PulseAll(objLockTest),然後查看軟件運行變化,
改後代碼:
private void button7_Click(object sender, EventArgs e)
{
this.Hide();
Console.WriteLine("[主線程] " + DateTime.Now.ToString() + "開啓子線程");
Thread cc = new Thread(C); cc.IsBackground = true; cc.Name = "[線程C]"; cc.Start();
Thread aa = new Thread(A); aa.IsBackground = true; aa.Name = "[線程A]"; aa.Start();
Thread bb = new Thread(B); bb.IsBackground = true; bb.Name = "[線程B]"; bb.Start();
Thread dd = new Thread(D); dd.IsBackground = true; dd.Name = "[線程D]"; dd.Start();
Thread ee = new Thread(E); ee.IsBackground = true; ee.Name = "[線程E]"; ee.Start();
Thread ff = new Thread(F); ff.IsBackground = true; ff.Name = "[線程F]"; ff.Start();
Console.ReadLine();
}
private static object objLockTest = new object();
private static void A()
{
Console.WriteLine("[線程A] 開啓...");
Thread.Sleep(100);
Console.WriteLine("[線程A] [就緒隊列]");
lock (objLockTest) //進入[就緒隊列]隊列
{
Console.WriteLine("[線程A] [持有鎖的線程]");
Thread.Sleep(1000);
Console.WriteLine("[線程A] Monitor.Pulse," + DateTime.Now.ToString("HH:mm:ss:fff"));
//Notifies a thread in the waiting queue of a change in the locked object's state.
Monitor.Pulse(objLockTest);
Thread.Sleep(100);
Console.WriteLine("[線程A] Monitor.Wait ," + DateTime.Now.ToString("HH:mm:ss:fff"));
//Releases the lock on an object and blocks the current thread until it reacquires the lock.
//(Monitor.Wait將本線程添加到[等待隊列]
//超時時間:線程進入就緒隊列之前等待的毫秒數,即從Wait 到Pulse之間的毫秒數,
// 若無超時時間,且無Pulse喚醒,則本線程一直會處於[等待隊列]
if (Monitor.Wait(objLockTest, 300))
Console.WriteLine("[線程A] 重新獲得該鎖(在指定的時間過期之前)" + DateTime.Now.ToString("HH:mm:ss:fff"));
else
Console.WriteLine("[線程A] 重新獲得該鎖(在指定的時間過期之後)" + DateTime.Now.ToString("HH:mm:ss:fff"));
Thread.Sleep(4000);
Console.WriteLine("[線程A] 退出..." + DateTime.Now.ToString("HH:mm:ss:fff"));
}
}
private static void B()
{
Console.WriteLine("[線程B] 開啓...");
Thread.Sleep(150);
Console.WriteLine("[線程B] [就緒隊列]");
lock (objLockTest)
{
Console.WriteLine("[線程B] [持有鎖的線程]");
Thread.Sleep(100);
Console.WriteLine("[線程B] Monitor.Wait," + DateTime.Now.ToString("HH:mm:ss:fff"));
if (Monitor.Wait(objLockTest, 3000))
Console.WriteLine("[線程B] 重新獲得該鎖(在指定的時間過期之前)" + DateTime.Now.ToString("HH:mm:ss:fff"));
else
Console.WriteLine("[線程B] 重新獲得該鎖(在指定的時間過期之後)" + DateTime.Now.ToString("HH:mm:ss:fff"));
Thread.Sleep(500);
Console.WriteLine("[線程B] 退出...");
}
}
private static void C()
{
Console.WriteLine("[線程C] 開啓...");
Thread.Sleep(130);
Console.WriteLine("[線程C] [就緒隊列]");
lock (objLockTest)
{
Console.WriteLine("[線程C] [持有鎖的線程]");
Thread.Sleep(100);
Console.WriteLine("[線程C] Monitor.Wait," + DateTime.Now.ToString("HH:mm:ss:fff"));
if (Monitor.Wait(objLockTest, 3000))
Console.WriteLine("[線程C] 重新獲得該鎖(在指定的時間過期之前)" + DateTime.Now.ToString("HH:mm:ss:fff"));
else
Console.WriteLine("[線程C] 重新獲得該鎖(在指定的時間過期之後)" + DateTime.Now.ToString("HH:mm:ss:fff"));
Thread.Sleep(500);
Console.WriteLine("[線程C] 退出...");
}
}
private static void D()
{
Console.WriteLine("[線程D] 開啓...");
Thread.Sleep(250);
Console.WriteLine("[線程D] [就緒隊列]");
lock (objLockTest)
{
Console.WriteLine("[線程D] [持有鎖的線程]");
Thread.Sleep(100);
Console.WriteLine("[線程D] Monitor.PulseAll, " + DateTime.Now.ToString("HH:mm:ss:fff"));
//Notifies a thread in the waiting queue of a change in the locked object's state.
Monitor.PulseAll(objLockTest);
Thread.Sleep(500);
Console.WriteLine("[線程D] 退出...");
}
}
private static void E()
{
Console.WriteLine("[線程E] 開啓...");
Thread.Sleep(300);
Console.WriteLine("[線程E] [就緒隊列]");
lock (objLockTest)
{
Console.WriteLine("[線程E] [持有鎖的線程]" + DateTime.Now.ToString("HH:mm:ss:fff"));
Thread.Sleep(500);
Console.WriteLine("[線程E] 退出...");
}
}
private static void F()
{
Console.WriteLine("[線程F] 開啓...");
Thread.Sleep(350);
Console.WriteLine("[線程F] [就緒隊列]");
lock (objLockTest)
{
Console.WriteLine("[線程F] [持有鎖的線程]" + DateTime.Now.ToString("HH:mm:ss:fff"));
Thread.Sleep(500);
Console.WriteLine("[線程F] 退出...");
}
}
軟件運行具體結果及對照如下:
從上面看Monitor.PulseAll爲將[等待隊列]所有的線程移到[就緒隊列],
[就緒隊列]中排序爲:原來排在最前的線程E,然後是以主線程開啓子線程的順序(start的順序)排序。
問:若是一個Monitor.Pulse呢?
答:線程Pulse後將[等待隊列] 最前的線程 移到[就緒隊列], 即默認將第一個調用Wait的線程移動到[就緒隊列]
部分代碼及截圖如下:
問:若是兩個Monitor.Pulse呢?
答:分別兩次將[等待隊列] 最前的線程 移到[就緒隊列],
[就緒隊列]中排序爲:原來排在最前的線程E,然後是這兩個子線程開啓的順序(start的順序)排序。
部分代碼及截圖如下:
問:若是三個Monitor.Pulse呢?
答:分別三次將[等待隊列] 最前的線程 移到[就緒隊列],
[就緒隊列]中排序爲:原來排在最前的線程E,然後是這兩個子線程開啓的順序(start的順序)排序。
部分代碼及截圖如下:
結論:
只有一個線程,則此線程爲Wait超時線程或[等待隊列]的首線程。
若只有一個Monitor.Pulse,則轉入[就緒隊列]的線程爲第一個Wait的線程。
若 有多個Monitor.Pulse,則轉入[就緒隊列]的線程的順序爲主線程開啓子線程的順序(start的順序)。
4.總結(Q&A)
從上面程序及運行結果得出如下結論:
<問1>若有多個wait同時起作用,那麼多個線程狀態在[等待隊列]中的排序是?
<答1>多個wait起作用後多個線程依次進入[等待隊列]狀態,即最先進入[等待隊列]的排在最前。
<問2> 單個Pulse作用是將[等待隊列] 最前的線程 移到[就緒隊列]的第幾位?
<答2>單個Pulse運行後從本程序上看,應該是[等待隊列] 最前的線程 大概率插隊到[就緒隊列]的第二位(如上軟件運行結果及對應釋義圖)
個人增加問題及答案:
<問 3>wait的超時時間及返回值的作用是?
<答 3>超時時間爲當前線程從[等待隊列]到進入[就緒隊列]的時間差,
超時時間作用如下:
a.超時時間爲0,則本線程直接進入[就緒隊列]
b.若已超時,則本線程會自動進入[就緒隊列]。
返回值的作用如下:
a.本線程重新獲取該鎖後,若在指定的時間過期之前從[等待隊列]進入[就緒隊列],返回值爲True,
b.本線程重新獲取該鎖後,若在指定的時間過期之後從[等待隊列]進入[就緒隊列],返回值爲False。
<問 4>線程如何從[等待隊列]進入[就緒隊列] ?
<答 4>兩種方式
a.第一種wait設定超時時間,超時後自動進入[就緒隊列] (如上軟件運行結果及對應釋義圖)
b.第二種其他線程運行Monitor.Pulse(同參數),將 [等待隊列]最前的線程移動到[就緒隊列]
<問 5>正常情況下Wait與Pulse的調用順序是?分別什麼影響?
<答 5>理論上應該是 某個線程先調用Monitor.Wait,然後另一線程再調用Monitor.Pulse,具體使用方法參考上面的代碼。
若[等待隊列]中無線程,另一線程先調用Monitor.Pulse,某個線程再調用Monitor.Wait,則Monitor.Pulse無作用(如上軟件運行結果及對應釋義圖中線程A),
且後面調用的Monitor.Wait可能會導致死鎖(參考鏈接微軟官方文檔[4])。爲防止死鎖,則建議在調用Monitor.Wait時設置足夠的超時時間。
<問 6>請問Monitor.PulseAll具體的作用是?
<答 6>作用爲將[等待隊列]的所有線程移到[就緒隊列]中,並放到[就緒隊列]的第二位。
若有多個線程,則以主線程開啓子線程的順序(start的順序)排序。
[等待隊列]中的排隊順序爲:調用Wait的順序依次排列
[就緒隊列]中的排隊順序爲:隊伍首線程,然後是“Wait超時,或調用後Pulse/PulseAll的線程”,再是其他線程。
若“Wait超時,或調用後Pulse/PulseAll的線程”
只有一個線程,則此線程爲Wait超時線程或[等待隊列]的首線程。
若有多個線程則排列順序爲:主線程開啓子線程的順序(start的順序)。
關於Wait和Pulse的問與答:
<問>線程Wait後如何回到[持有鎖的線程] ?
<答>當前線程運行到wait後進入了[等待隊列],而本線程若想重新進入[持有鎖的線程]則必須先轉爲[就緒隊列]狀態並排堆,只有進入[就緒隊列]且排隊後纔有可能轉爲[持有鎖的線程]。
<問>若wait需要設超時時間嗎?
<答>我們都知道線程運行到wait後則進行到[等待隊列],需要通過Monitor.Pulse(同參數)或超時時間進入[就緒隊列],否則本線程就會一直處於[等待隊列]。
<問>Monitor.Pulse會將線程移到[就緒隊列]的哪裏?
<答> 個人認爲會直接移動到[就緒隊列]的第二位,即當前狀態爲(排隊中)的第二個
Monitor.Pulse後會將同參數中處於[等待隊列] 最前的線程移動[就緒隊列],
而Monitor.PulseAll會將同參數中處於[等待隊列] 所有線程移到[就緒隊列]
編譯環境:Visual Studio 2012
編輯框架:.NET Framework 4.0
編程語言:C#
源代碼鏈接:https://download.csdn.net/download/shengmingzaiyuxuexi/12327588
參考鏈接
[1]:https://docs.microsoft.com/zh-cn/dotnet/standard/threading/managed-threading-best-practices
[2]:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.monitor?view=netframework-4.8
[3]:https://docs.microsoft.com/en-us/dotnet/api/system.threading.monitor?view=netframework-4.8
[4]:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.monitor.pulse?view=netframework-4.8
[5]:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.monitor.wait?view=netframework-4.8
有錯誤,請指正,有疑問,請留言,與君共勉,共同進步!
謝老闆的觀,看您的肯定就是我創作的最大動力,下期見!