程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> C#中Thread.Join()的理解

C#中Thread.Join()的理解

編輯:C#基礎知識

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

Thread.Join()在MSDN中的解釋很模糊:Blocks the calling thread until a thread terminates

有兩個主要問題:1.什麼是the calling thread?

                       2.什麼是a thread?

       首先來看一下有關的概念: 我們執行一個.exe文件實際上就是開啟了一個進程,同時開啟了至少一個線程

但是真正干活的是線程,就好比一個Team有好幾個人,但是真正干活的是人不是Team.

      具體到代碼來說,以控制台程序為例:程序Test.exe從Main函數開始運行,實際上是有一個線程

在執行Main函數,我們稱作MainThread.假如我們在Main函數中聲明了一個Thread,稱作NewThread,並且調用了

NewThread.Start()的方法,那麼 MainThread在處理Main函數裡面的代碼時遇到NewThread.Start()時,就會

去調用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快點啊,我在等你幾分鐘,你在默默唧唧干不完我就不等你了,我先去了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved