


彼年豆蔻,谁许谁地老天荒。
在多线程环境下,我们可能会需要等待开辟的线程执行完后,再去执行某个方法,例如输出并行计算结果等。
但是在多线程下,线程的执行是不阻塞主线程的,这点其实也是多线程的优势,提高代码执行效率,不必相互等待可以并行执行
例如如下代码:
- private void button1_Click(object sender, EventArgs e)
- {
- for (int i = 0; i < 3; i++)
- {
- Task task = new Task((obj) =>
- {
- System.Threading.Thread.Sleep(500);
- MessageBox.Show(obj + "");
- },i);
- task.Start();
- }
-
- MessageBox.Show("线程执行完毕了");
- }
当点击按钮开启线程后,先弹出来的不是开启的线程弹窗,而是主线程的线程弹窗。
现在我们来通过某些方法,实现可以在多线程执行完毕后在执行自己的逻辑
几种常用的处理方法
1:使用Task.WaitAll (会阻塞主线程)
可以使用Task.WaitAll让主线程一直等待开辟的线程,直到所有子线程都执行完后再执行主线程逻辑
-
- private void button1_Click(object sender, EventArgs e)
- {
- Task[] tasks = new Task[3];
-
- for (int i = 0; i < 3; i++)
- {
- Task task = new Task((obj) =>
- {
- System.Threading.Thread.Sleep(500);
- MessageBox.Show(obj + "");
- },i);
-
- tasks[i] = task;
- task.Start();
- }
-
- Task.WaitAll(tasks);
- MessageBox.Show("线程执行完毕了");
- }
Task.WaitAll 是一个等待的过程,一旦全部执行完毕了,就继续往下执行,这里是阻塞的
2:使用Task.WhenAll(不会阻塞主线程)
Task.WhenAll和Task.WaitAll类似都可以做到线程执行后在向下执行,但是wait是等待也就是会阻塞主线程,而when表示当的意思,就是当子线程都执行完后在执行一个回调函数。可以把子线程执行完毕后想执行的代码放入该回调函数里边。
- private void button1_Click(object sender, EventArgs e)
- {
- Task[] tasks = new Task[3];
-
- for (int i = 0; i < 3; i++)
- {
- Task task = new Task((obj) =>
- {
- System.Threading.Thread.Sleep(2000);
- MessageBox.Show(obj + "");
- }, i);
-
- tasks[i] = task;
- task.Start();
- }
-
- Task.WhenAll(tasks).ContinueWith(a =>
- {
- MessageBox.Show("线程执行完毕了");
- });
- MessageBox.Show("主线程被执行了");
- }
3:使用Parallel.Invoke或者 Parallel.For(会阻塞主线程)
Parallel.Invoke或者 Parallel.For可以很方便的开辟多线程并行执行,自动会阻塞多线程。所以他后面写的代码会
自动等待子线程执行完毕后再执行
- private void button2_Click(object sender, EventArgs e)
- {
- //开辟子线程,并行执行
- Parallel.Invoke(() =>
- {
- System.Threading.Thread.Sleep(1500);
- MessageBox.Show("线程A");
- }, () =>
- {
-
- System.Threading.Thread.Sleep(1500);
- MessageBox.Show("线程B");
- });
-
- //开辟子线程,并行执行
- Parallel.For(0, 3, (a) =>
- {
- System.Threading.Thread.Sleep(1500);
- MessageBox.Show("线程" + a);
- });
-
- MessageBox.Show("线程执行完毕");
- }
4:自己另开线程,监控线程状态(不会阻塞主线程)
其实我们可以单独另外开辟一个新的线程了,用来监控所有子线程的运行状态,当这些被监控的线程都执行完毕后即可执行自己的逻辑,当然也可以封装一个回调函数用于方便调用。
线程的状态有很多:例如Created(已经创建),Running(运行中),RanToCompletion(运行完毕)等
我们就可以利用这些线程状态来做一些自定义操作。例如这里的等待线程执行完毕等。
- static void Main(string[] args)
- {
- Task task = new Task(() =>
- {
- System.Threading.Thread.Sleep(2000);
- Console.WriteLine("线程执行完了");
- });
- task.Start();
-
-
- Console.WriteLine("-------开始监听单线程执行-------");
- //一个单独的线程 监控其他线程的状态
- Task monitor_task = new Task(() =>
- {
- while (true)
- {
- if (task.Status == TaskStatus.RanToCompletion)
- {
- Console.WriteLine("监控到线程执行完了");
- break;
- }
- }
- });
- monitor_task.Start();
-
- Console.ReadLine();
- }
监控多个线程其实也是一样,监控的时候判断执行完成线程的个数就行了
- static void Main(string[] args)
- {
- Task[] tasklist = new Task[10];
-
- Dictionary<object, object> dic = new Dictionary<object, object>();
- for (int i = 0; i < 10; i++)
- {
- Task task = new Task((a) =>
- {
- System.Threading.Thread.Sleep(1000);
- dic.Add(a, a);
- }, i);
-
- tasklist[i] = task;
- task.Start();
- }
-
- //用户监控其他线程的状态
- Task monitor_task = new Task(() =>
- {
- //监控线程的个数
- int i = 0;
- while (true)
- {
- i = 0;
- foreach (Task item in tasklist)
- {
- if (item.Status == TaskStatus.RanToCompletion)
- {
- i++;
- }
- }
- if (i == 10)
- {
- Console.WriteLine("所有线程执行完毕" + dic.Count);
- break;
- }
- }
- });
- monitor_task.Start();
- Console.ReadLine();
- }
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)
饰心
学到了
是伍尚金哇_v
不是Task不用task.start()了吗![[吃惊]](http://www.tnblog.net/content/static/layui/images/face/6.gif)