故如虹,知恩;故如月,知明
排名
6
文章
6
粉丝
16
评论
8
{{item.articleTitle}}
{{item.blogName}} : {{item.content}}
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2024TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
欢迎加群交流技术

等待所有线程执行完后,在执行某个方法

10481人阅读 2019/4/22 22:24 总访问:3838349 评论:3 收藏:1 手机
分类: 多线程

彼年豆蔻,谁许谁地老天荒。



在多线程环境下,我们可能会需要等待开辟的线程执行完后,再去执行某个方法,例如输出并行计算结果等。

但是在多线程下,线程的执行是不阻塞主线程的,这点其实也是多线程的优势,提高代码执行效率,不必相互等待可以并行执行

例如如下代码:

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



欢迎加群讨论技术,群:677373950(满了,可以加,但通过不了),2群:656732739

评价