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

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

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

例如如下代码:

   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张图片

  当点击按钮开启线程后,先弹出来的不是开启的线程弹窗,而是主线程的线程弹窗。

 

 现在我们来通过某些方法,实现可以在多线程执行完毕后执行自己的逻辑

一般的处理方法有以下几种

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(运行完毕)等

等待所有线程执行完后,执行某个方法_第2张图片

我们就可以利用这些线程状态来做一些自定义操作。例如这里的等待线程执行完毕等。

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 dic = new Dictionary();
            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();      
        }

 

 

你可能感兴趣的:(.net)