将多个线程在线程池中运行

知识点保温

引用一下微软官网的介绍:

线程池: https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.threadpool?redirectedfrom=MSDN&view=netframework-4.7.2


直接上Demo

多线程运行 VS 单线程运行

    /// <summary>/// 高效多线程测试/// </summary>public class ThreadTestController : ApiController{static AutoResetEvent autoResetEvent = new AutoResetEvent(false);private static string keySet = System.Configuration.ConfigurationManager.AppSettings["KeySetting"];/// <summary>/// 多线程运行 -- 线程池/// </summary>/// <returns></returns>public ApiReponseBaseModel MultThreads(){ApiReponseBaseModel result = new ApiReponseBaseModel();List<string> list = new List<string>() { "一", "二", "三", "四", "", "五", "六", "七" };ApiReponseBaseModel masterVal = new ApiReponseBaseModel() { Id = 1, Success = false, Message = "one" };List<string> newList = new List<string>();try{int i = 0;foreach (var item in list){try{if (item == "四") throw new Exception("人造异常");ThreadPool.QueueUserWorkItem(new WaitCallback(delegate (object obj){if (string.IsNullOrEmpty(item)) { i++; newList.Add((i).ToString() + ":" + "为空了"); return; }  //保证每个子线程都有执行 i++try{#region ApiReponseBaseModel val = new ApiReponseBaseModel{Id = masterVal.Id,Success = masterVal.Success,Message = masterVal.Message};#endregionval.Message = item;Thread.Sleep(500);lock (newList){newList.Add(i.ToString() + ":" + val.Message);}}catch (Exception ex){newList.Add((i+1).ToString() + ":" + ex.Message);}finally{if (++i == list.Count) autoResetEvent.Set();}}), null);}catch (Exception ex){i++;    //发生异常,一定要记得 i++newList.Add(i.ToString() + ":" + ex.Message);continue;}//finally  //【误区】千千万万不要在这里写逻辑判断(i == list.Count 或者写 i++),这个finally是主线程的,不一定会在子线程之后执行的//{//    i++;//    if (i == list.Count) autoResetEvent.Set();//}
                }autoResetEvent.WaitOne();newList.Add("the end");result.Data = newList;}catch (Exception ex){throw ex;}return result;}/// <summary>/// 单线程运行/// </summary>/// <returns></returns>public ApiReponseBaseModel SingleThread(){ApiReponseBaseModel result = new ApiReponseBaseModel();List<string> list = new List<string>() { "一", "二", "三", "四", "", "五", "六", "七" };ApiReponseBaseModel masterVal = new ApiReponseBaseModel() { Id = 1, Success = false, Message = "one" };List<string> newList = new List<string>();int i = 0;foreach (var item in list){if (string.IsNullOrEmpty(item)) { i++; newList.Add((i).ToString() + ":" + "为空了"); continue; }#region ApiReponseBaseModel val = new ApiReponseBaseModel{Id = masterVal.Id,Success = masterVal.Success,Message = masterVal.Message};#endregionval.Message = item;Thread.Sleep(500);newList.Add(i.ToString() + ":" + val.Message);i++;}newList.Add("the end");result.Data = newList;return result;}}

结果:

解析:

1、以上两个方法的运行,我们都在方法中休眠了,用以突显出多线程异步执行达到运行更快的效果。

2、在第一个方法(多线程运行 -线程池)中,用到了线程池,其关键在于 AutoResetEvent 的使用,它的.Set() 和 WaitOne() 是关键点。

WaitOne() 会阻塞当前的线程,而等当前 WaitHandle 发来的信息,Set() 方法就是发出信号的。

3、那么很重要的地方来了,就是怎么在逻辑中表达,所需要计算的数据和执行的进程都已经执行完了,而在恰当的地方适当的时候发起信号,激活主线程。

4、以上多线程方法中,我们还用到了个 lock 锁,这也是极其微妙关键的。我们的多个子线程运行的程序模块中,都有访问了一个共同的对象 newList。newList 是主线程的一个 引用类型变量,为了防止多个线程在同一个时间点对这个变量进行更改操作(Add),

而引发的异常错误,我们在做这类操作的时候,给这个共同的资源(newList)加上锁,让这样的操作一个接着一个来。

进程中的 val 这个变量,变量类型是(ApiReponseBaseModel),也是个引用类型。我们不在子进程中直接用主线程的 masterVal 变量,也是这个原因,防止多个子线程同时对共同资源做修改操作。

5、WaitHandler 类的小图解


我们再试个任务工厂的Demo

知识点保温

任务工厂的知识保温链接:https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskfactory?view=netframework-4.7.2

需要温习任务工厂的小伙伴们可以进入以上链接,吸食日夜精华


直接上菜

        /// <summary>/// 多线程运行 -- 任务工厂/// </summary>/// <returns></returns>public ApiReponseBaseModel TaskFactory(){ApiReponseBaseModel result = new ApiReponseBaseModel();List<string> list = new List<string>() { "一", "二", "三", "四", "", "五", "六", "七" };ApiReponseBaseModel masterVal = new ApiReponseBaseModel() { Id = 1, Success = false, Message = "one" };List<string> newList = new List<string>();List<Task> taskList = new List<Task>();int i = 0;list.ForEach(p =>{taskList.Add(Task.Factory.StartNew(() =>{if (string.IsNullOrEmpty(p)) { i++; newList.Add((i).ToString() + ":" + "为空了"); return; }  //保证每个子线程都有执行 i++try{if (p == "四") throw new Exception("人造异常");#region ApiReponseBaseModel val = new ApiReponseBaseModel{Id = masterVal.Id,Success = masterVal.Success,Message = masterVal.Message};#endregionval.Message = p;Thread.Sleep(500);lock (newList){newList.Add(i.ToString() + ":" + val.Message);}}catch (Exception ex){newList.Add((i + 1).ToString() + ":" + ex.Message);}}));//taskList.Add(Task.Factory.StartNew(fn =>//{//}, null));
            });Task finalTask = Task.Factory.ContinueWhenAll(taskList.ToArray(), fn => {newList.Add("finallyTask the end");});finalTask.Wait();newList.Add("main thread the end");result.Data = newList;return result;}

效果:

解析:

1、我们在任务工厂里边搞了几个任务,每个任务我们都休眠,模仿长时间运行效果。

2、任务工厂的关键在于 ContinueWhenAll() 方法。顾名思义,当该方法参数所指的任务都执行的时候,执行这一方法,这个方法返回一个任务,我们定义一个任务变量(finalTask)来接收。

紧接着,我们放这个变量(finalTask)进行等待,finalTask.Wait()。


小总结

通过以上三个方法的比较

1、多线程比单线程是有优势的,通常情况下运行时间是会更快的,除非服务器爆了

2、在易于编写使用的角度来说,个人觉得任务工厂的办法会比线程池的方法好一些。

3、多读书,多敲码。            ----- 致爱码仕 & 牧码人


author:韦小明

本文路径:http://www.cnblogs.com/youler/p/9845473.html


转载于:https://www.cnblogs.com/youler/p/9845473.html

线程池和任务工厂实现多线程异步运行相关推荐

  1. springboot微服务实战:初探异步线程池(四种创建多线程对比)

    四种多线程对比(异步) 创建和初始化多线程的几种方式1.继承Thread2.实现Runnable接口3.实现Callable接口 + FutureTask(可以拿到返回结果,可以处理异常)4.线程池 ...

  2. Java多线程系列(三):Java线程池的使用方式,及核心运行原理

    之前谈过多线程相关的4种常用Java线程锁的特点,性能比较.使用场景,今天主要分享线程池相关的内容,这些都是属于Java面试的必考点. 为什么需要线程池 java中为了提高并发度,可以使用多线程共同执 ...

  3. java开源线程池_线程池 - Java 并发性和多线程 - UDN开源文档

    线程池 线程池(Thread Pool)对于限制应用程序中同一时刻运行的线程数很有用.因为每启动一个新线程都会有相应的性能开销,每个线程都需要给栈分配一些内存等等. 我们可以把并发执行的任务传递给一个 ...

  4. python线程池并发_python 并发编程多线程之进程池/线程池

    一.验证GIL锁的存在 Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行.虽然 Python 解释器中可以"运行"多个线程,但在任意时刻只有一个线程在解释器中运行 ...

  5. java 线程池 状态_【Java多线程】线程状态、线程池状态

    线程状态: 线程共包括以下5种状态. 1. 新建状态(New)线程对象被创建后,就进入了新建状态.例如,Thread thread = new Thread(). 2. 就绪状态(Runnable)也 ...

  6. 手写Java线程池_超详细解说_绝对能运行_代码超详细注释

    线程池 问题背景 只是单纯使用 new Thread(runnable).start(); 的方式创建线程, 将会导致严重的程序性能问题: 1.线程创建, 销毁需要消耗很大的系统资源; 2.虚拟机创建 ...

  7. python3线程池爬虫_python3爬虫中多线程的优势总结

    有些小伙伴跟小编讨论了python中使用多线程原理的问题,就聊到了关于python多线程的弊端问题,这点可能在使用的过程中大家会能感觉到.而且之前讲过的GIL也是对python多线程的一种限制.那么, ...

  8. python线程只能启动一次_python多线程只能运行一个线程的问题

    问题描述: 使用 python threading.Thread() 建立两个线程,启动后只有线程1在运行,线程2不运行. 问题代码 import time, threading def run_th ...

  9. java多线程及线程池使用

    Java多线程及线程池的使用 Java多线程 一.Java多线程涉及的包和类 二.Java创建多线程的方式 三.Java线程池 1. 创建线程池ThreadPoolExecutor的7个参数 2. 线 ...

最新文章

  1. BERT大火却不懂Transformer?读这一篇就够了 原版 可视化机器学习 可视化神经网络 可视化深度学习...20201107
  2. Docker从入门到实践笔记(一)
  3. Mysql在离线安装时启动失败:mysql服务无法启动,服务没有报告任何错误
  4. 【数据结构与算法】之深入解析“字符串相乘”的求解思路与算法示例
  5. 我的世界服务器修改成创造,我的世界怎么创建领域
  6. 槽点才是G点,LiveVideoStack主编是如何吐槽内容的?
  7. Flask设置、获取、删除cookies
  8. N个Linux耍酷命令,手把手教你如何技术撩妹!
  9. java异常处理:finally中不要return
  10. nginx同一域名下部署多个vue项目
  11. 全局最小割Stoer-Wagner算法
  12. vSphere虚拟机磁盘热扩容
  13. 大学计算机信息技术实验与测试教程第2版,大学信息技术实验指导
  14. 《延禧攻略》的配色,简直美到爆!
  15. 【数学建模】灰色模型
  16. excel 中英文 显示星期,月份
  17. 科目三考试挂掉原因分析
  18. 学生党必备读书笔记app推荐
  19. 机器学习基石-05-3-Effective Number of Hypotheses
  20. Autofill安装使用

热门文章

  1. 创建图片mat_OPENCV(二)——Mat类与几个函数的简介
  2. android markdown 框架,Android Studio MarkDown风格README的正确打开姿势
  3. android 内存检测开源库 翻译,开源 | 哈佛大学NLP组开源神经机器翻译工具包OpenNMT:已达到生产可用水平...
  4. centen os7 源码安装git2.17.0
  5. 依赖注入和控制反转的理解
  6. js延时函数_JS 函数的执行时机
  7. 全局系统性地把握客户感知-建立VOC
  8. pmos低电平驱动_三极管和MOS管驱动电路的正确用法
  9. Git——三大分区【工作区 / 暂存区 / 版本区】
  10. w3c html.css,W3C教程(6):W3C CSS 活动