最近在项目中使用多线程,可是对多线程的一些用法和概念还有有些模棱两可,为了搞清楚查阅了一写资料,写下这篇日志加深理解吧。多线程
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快点啊,我在等你几分钟,你在默默唧唧干不完我就不等你了,我先去了。