C#中Thread.Join()的理解

最近在項目中使用多線程,可是對多線程的一些用法和概念還有有些模棱兩可,爲了搞清楚查閱了一寫資料,寫下這篇日誌加深理解吧。多線程

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毫秒,因此執行結果應該是:

image

從結果中能夠看到,先執行的主線程,而後執行的新線程,若是咱們想讓新線程執行完畢後再繼續執行主線程呢?這時就用到了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();

        }

這段代碼執行的結果爲:

image

此次打印的結果和沒加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();

        }

輸出結果爲:

image

雖然第二個線程在第一個線程剛剛啓動後就調用了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();

        }

改代碼的執行結果是:

image

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();
        }

改代碼的執行結果爲:

image

因而可知,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快點啊,我在等你幾分鐘,你在默默唧唧幹不完我就不等你了,我先去了。

相關文章
相關標籤/搜索