本文主要描述在.netframework中(实验环境.netframework版本为4.6.1)提供两种方式等待多个子线程执行完毕。

  • ManualResetEvent

在多线程中,将ManualResetEvent实例作为方法传入,线程执行完毕后可以设置标志位来标识当前线程已经执行完毕。代码如下:

  List<ManualResetEvent> manualResetEvents = new List<ManualResetEvent>();
/// <summary>
/// ManualResetEvent标志多线程是否执行完毕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_ManualResetEvent_Click(object sender, EventArgs e)
{
// SetBtnEnabled(false);
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = ; i < threadCount; i++)
{
ManualResetEvent manualReset = new ManualResetEvent(false);
manualResetEvents.Add(manualReset);
ThreadPool.QueueUserWorkItem(ManualResetEventMethod, manualReset);
}
//等待所有线程执行完毕
WaitHandle.WaitAll(manualResetEvents.ToArray());
//暂停watch,获取多线程执行时间
watch.Stop();
long time = watch.ElapsedMilliseconds;
lab_time.Text = time.ToString(); // SetBtnEnabled(true); //释放句柄
manualResetEvents.Clear();
} private void ManualResetEventMethod(object obj)
{
Thread.Sleep();
ManualResetEvent mre = (ManualResetEvent)obj;
mre.Set();
}

注意:

在WaitHandle.WaitAll方法中,等待的句柄不能超过64,所以每次用完后,需要手动调用Clear方法进行释放。

如果等待的线程超过64个,可以参考博客:https://www.cnblogs.com/xiaofengfeng/archive/2012/12/27/2836183.html,在该博客中,通过对ManualResetEvent的封装,能够使等待的句柄超过64(测试环境下一次起1000个线程,没有问题)

  • Monitor

在主线程中通过Monitor.Wait(locker)达到阻塞的目的,子线程执行完毕通过 Monitor.Pulse(locker)通知主线程,直到所有子线程执行完成,主线程再继续执行,代码如下:

         object locker = new object();
int threadCount = ;
int finshCount = ;
/// <summary>
/// Monitor线程之间同步标记多线程执行完毕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_Monitor_Click(object sender, EventArgs e)
{
finshCount = ;
SetBtnEnabled(false);
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = ; i < threadCount; i++)
{
Thread trd = new Thread(new ParameterizedThreadStart(MonitorMethod));
trd.Start(i);
}
lock (locker)
{
while (finshCount != threadCount)
{
Monitor.Wait(locker);//等待
}
}
//所有线程执行完毕,获取执行时间
watch.Stop();
long time = watch.ElapsedMilliseconds;
lab_time.Text = time.ToString(); SetBtnEnabled(true);
} private void MonitorMethod(object obj)
{
Thread.Sleep();
lock (locker)
{
finshCount++;
Monitor.Pulse(locker); //完成,通知等待队列,告知已完,执行下一个。
}
}

在一次开启10、1000个线程两种环境下,分别测试以上两种方式,ManualResetEvent在多次执行时,前几次耗时会比较大,后续耗时会减少并且稳定下来,接近 Monitor的速度。相对而言,Monitor的效率更高。

如果了解过go语言,会发现通过sync包下的WaitGroup也可以达到同样的目的,代码如下:

package main

import (
"fmt"
"sync"
"time"
) var wg sync.WaitGroup
var count = 1000 func main() { startTime := time.Now().Unix()
wg.Add(count)
for i := 0; i < count; i++ {
go func() {
defer wg.Done()
time.Sleep(time.Second)
}()
}
fmt.Println("waiting for all goroutine")
wg.Wait() endTime := time.Now().Unix() fmt.Printf("all goroutine is done! time:%v s", (endTime-startTime)) }

  相较而言,go语言的协程效率最高

netframework中等待多个子线程执行完毕并计算执行时间的更多相关文章

  1. Java多线程--让主线程等待所有子线程执行完毕

    数据量很大百万条记录,因此考虑到要用多线程并发执行,在写的过程中又遇到问题,我想统计所有子进程执行完毕总共的耗时,在第一个子进程创建前记录当前时间用System.currentTimeMillis() ...

  2. java主线程等待所有子线程执行完毕在执行(常见面试题)

    java主线程等待所有子线程执行完毕在执行(常见面试题) java主线程等待所有子线程执行完毕在执行,这个需求其实我们在工作中经常会用到,比如用户下单一个产品,后台会做一系列的处理,为了提高效率,每个 ...

  3. c#等待所有子线程执行完毕方法

    当我们在使用线程中,你会发现主线结束后子线程的结果才显示出来.现在我要等待所以子线程结束,然后在显示结果,怎么做呢? 方法如下: 1.使用 ManualResetEvent,代码如下:  using  ...

  4. Java主线程等待所有子线程执行完毕再执行解决办法(转)

    方法一: Thread.join()方法,亲测可行,thread.join()方法 Vector<Thread> ts = new Vector<Thread>(); for  ...

  5. CountDownLatch用法---等待多个线程执行完才执行

    CountDownLatch用法---等待多个线程执行完才执行 CountDownLatch用法---等待多个线程执行完才执行 CountDownLatch用法---等待多个线程执行完才执行 Coun ...

  6. C# 多线程join的用法,等待多个子线程结束后再执行主线程

    等待多个子线程结束后再执行主线程 class MultiThread{ #region join test public void MultiThreadTest() { Thread[] ths = ...

  7. java并发编程学习:如何等待多个线程执行完成后再继续后续处理(synchronized、join、FutureTask、CyclicBarrier)

    多线程应用中,经常会遇到这种场景:后面的处理,依赖前面的N个线程的处理结果,必须等前面的线程执行完毕后,后面的代码才允许执行. 在我不知道CyclicBarrier之前,最容易想到的就是放置一个公用的 ...

  8. Java主线程在子线程执行完毕后再执行

    一.join() Thread中的join()方法就是同步,它使得线程之间由并行执行变为串行执行. public class MyJoinTest { public static void main( ...

  9. Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执行

    Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执行 Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执 ...

随机推荐

  1. LeetCode(289)Game of Life

    题目 According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a cel ...

  2. golang(go语言)调试和查看gc信息,以及gc信息解析

    这里记录一下调试golang gc的方法 启用gc打印: # GODEBUG=gctrace=1 go run ./main.go 程序启动后gc将打印如下信息: gc 65 @16.996s 0%: ...

  3. selenium2常用API介绍

    我们模拟web操作都是基于元素来操作的,我们首先要先确定元素,然后这个元素下对应的方法就可以看WebElement的方法. 1.点击操作 WebElement button=driver.findEl ...

  4. 详解Python中的相对导入和绝对导入

    Python 相对导入与绝对导入,这两个概念是相对于包内导入而言的.包内导入即是包内的模块导入包内部的模块. Python import 的搜索路径 在当前目录下搜索该模块 在环境变量 PYTHONP ...

  5. JSON Undefined 问题

    在IE6和IE7浏览器下或在IE8-IE10浏览器文档模式为IE7及以下时,控制台会报错:JSON is undefined. 这种错误在IE6和IE7浏览器下出现很正常,因为JSON在IE8+浏览器 ...

  6. I love you

    while(true) { printf("I love you"); } 字母解析 I-Inject--投入 投入,这个投入有很多概念,有对自己所爱的人,投入自己所有的感情,让你 ...

  7. web安全测试---WebScarab工具介绍

    1.1      Webscarab [功能] WebScarab是一个用来分析使用HTTP和HTTPS协议的应用程序框架.其原理很简单,WebScarab可以记录它检测到的会话内容(请求和应答),并 ...

  8. webdriver高级应用- 操作富文本框

    富文本框的技术实现和普通的文本框的定位存在较大的区别,富文本框的常见技术用到了Frame标签,并且在Frame里面实现了一个完整的HTML网页结构,所以使用普通的定位模式将无法直接定位到富文本框对象. ...

  9. Pycharm脚本通用部分设置

    Python脚本经常要设置同样的注释内容,Pycharm里面提供的模板可以很好的实现这个需求. 查找: File->settings->Editor->File and Code T ...

  10. [错误解决]刚拿到的服务器vim退格键(backspace)失灵

    刚拿到的服务器vim退格键(backspace)失灵: 解决方案: 在主目录下建立.vimrc 覆盖/etc/vimrc的配置 .vimrc 与 /etc/vimrc的区别: 在启动的时候vim会读取 ...