在多线程环境下,我们可能会需要等待开辟的线程执行完后,再去执行某个方法,例如输出并行计算结果等。
但是在多线程下,线程的执行是不阻塞主线程的,这点其实也是多线程的优势,提高代码执行效率,不必相互等待可以并行执行
例如如下代码:
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