最近在項目中使用多線程,可是對多線程的一些用法和概念還有有些模棱兩可,爲了搞清楚查閱了一寫資料,寫下這篇日誌加深理解吧。多線程
Thread.Join()在MSDN中的解釋很模糊:Blocks the calling thread until a thread terminates函數
有兩個主要問題:1.什麼是the calling thread?測試
2.什麼是a thread? spa
首先來看一下有關的概念: 咱們執行一個.exe文件實際上就是開啓了一個進程,同時開啓了至少一個線程,線程
可是真正幹活的是線程,就比如一個Team有好幾我的,可是真正幹活的是人不是Team.翻譯
具體到代碼來講,以控制檯程序爲例:程序Test.exe從Main函數開始運行,其實是有一個線程日誌
在執行Main函數,咱們稱做MainThread.假如咱們在Main函數中聲明瞭一個Thread,稱做NewThread,而且調用了code
NewThread.Start()的方法,那麼 MainThread在處理Main函數裏面的代碼時遇到NewThread.Start()時,就會blog
去調用NewThread.進程
基於上面的討論,咱們能夠得出結論:在咱們剛纔的例子中the calling thread就是MainThread,而a thread
指的洽洽就是MainThread調用的NewThread線程。
如今回到MSDN的解釋,咱們能夠這麼翻譯:當NewThread調用Join方法的時候,MainThread就被中止執行,
直到NewThread線程執行完畢。這樣就好理解了。
static void Main(string[] args) { Thread thread1 = new Thread(new ThreadStart(()=> { Thread.Sleep(500); Console.WriteLine("我是新線程打印的!"); })); thread1.Start(); Console.WriteLine("我是主線程打印的!"); Console.Read(); }
在Main函數中開啓一個新的線程執行NewFunc方法,在方法中先休息500毫秒而後打印一段標誌語。雖然thread1.Start()先於主線程的打印語句,可是新線程休息了500毫秒,因此執行結果應該是:
從結果中能夠看到,先執行的主線程,而後執行的新線程,若是咱們想讓新線程執行完畢後再繼續執行主線程呢?這時就用到了Thread.Join(),咱們在thread1.Start()後面添加thread1.Join(),這樣就會先執行完新線程後再去執行主線程。
static void Main(string[] args) { Thread thread1 = new Thread(new ThreadStart(()=> { Thread.Sleep(500); Console.WriteLine("我是新線程打印的!"); })); thread1.Start(); thread1.Join(); Console.WriteLine("我是主線程打印的!"); Console.Read(); }
這段代碼執行的結果爲:
此次打印的結果和沒加thread1.Join()的輸出結果恰好相反。
到此咱們能夠得出結論,當調用Thread.Join()後,主線程是被阻塞了的,直到新線程執行完畢才繼續執行,這是能夠確定的,但是咱們目前只開了一個線程,若是在開一個線程會怎麼樣呢?咱們接着測試:
static void Main(string[] args) { Thread thread1 = new Thread(new ThreadStart(()=> { for (int i = 0; i < 10; i++) { Thread.Sleep(100); Console.WriteLine("我是第1個線程打印的!"); } })); Thread thread2 = new Thread(new ThreadStart(() => { for (int i = 0; i < 10; i++) { Thread.Sleep(100); Console.WriteLine("我是第2個線程1打印的!"); } })); thread2.Start(); thread1.Start(); thread2.Join(); thread1.Join(); Console.WriteLine("我是主線程打印的!"); Console.Read(); }
輸出結果爲:
雖然第二個線程在第一個線程剛剛啓動後就調用了Join()可是並無阻塞第一個線程的執行,由此能夠驗證the calling thread,應爲第二個線程是由主線程開啓的,因此只能阻塞主線程,而不能阻塞其餘線程,下面再接着實驗在線程中再開一個新的線程:
static void Main(string[] args) { Thread thread1 = new Thread(new ThreadStart(()=> { Thread thread11 = new Thread(new ThreadStart(() => { for (int i = 0; i < 10; i++) { Thread.Sleep(100); Console.WriteLine("我是第1-1個線程1打印的!"); } })); thread11.Start(); for (int i = 0; i < 10; i++) { Thread.Sleep(100); Console.WriteLine("我是第1個線程打印的!"); } })); thread1.Start(); Console.WriteLine("我是主線程打印的!"); Console.Read(); }
改代碼的執行結果是:
thread1和thread11是同步執行的,因爲thread11是由thread1開啓的,下面調用thread11在看看結果:
static void Main(string[] args) { Thread thread1 = new Thread(new ThreadStart(()=> { Thread thread11 = new Thread(new ThreadStart(() => { for (int i = 0; i < 10; i++) { Thread.Sleep(100); Console.WriteLine("我是第1-1個線程1打印的!"); } })); thread11.Start(); thread11.Join(); for (int i = 0; i < 10; i++) { Thread.Sleep(100); Console.WriteLine("我是第1個線程打印的!"); } })); thread1.Start(); Console.WriteLine("我是主線程打印的!"); Console.Read(); }
改代碼的執行結果爲:
因而可知,thread11.Join()方法是阻塞了thread1的,並無阻塞主線程。再一次驗證the calling thread指的是開啓新線程的那個線程,而不必定是主線程。
此外,Thread.Join()還有兩個重載方法:
public bool Join(TimeSpan timeout);
public bool Join(int millisecondsTimeout);
兩個方法的參數不同可是效果是同樣的,目的是阻塞the calling thread的必定的時間,若是過了這個時間子線程尚未執行完畢,那麼the calling thread就會接着執行。例如:我中午叫個同事一塊兒去吃飯,可是他手頭還有點工做磨磨唧唧的一直沒有作完,若是是Join()的話我就一直等着,直到他作完我倆一塊兒去吃飯,而Join(TimeSpan timeout)和Join(int millisecondsTimeout)就是,你Y快點啊,我在等你幾分鐘,你在默默唧唧幹不完我就不等你了,我先去了。