Task是.NET 3.0中推出的,是基于ThreadPool封装的,里面的线程都是来自于ThreadPool。

1、使用Run()方法启动线程

F12查看Run()方法的定义:

发现Run()方法的参数是一个Action类型的委托,那么可以使用下面的方式启动多线程:

 // 使用Run()方法启动线程
 Task.Run(() => this.DoSomethingLong("btnTask_Click1"));
 Task.Run(() => this.DoSomethingLong("btnTask_Click2"));

2、使用TaskFactory的StartNew()方法

 // 使用TaskFactory启动
 TaskFactory taskFactory = Task.Factory;
 taskFactory.StartNew(() => this.DoSomethingLong("btnTask_Click3"));

3、使用Task的构造函数启动

 // 使用构造函数启动
 Task task= new Task(() => this.DoSomethingLong("btnTask_Click4"));
 task.Start();

效果:

下面来看看一个案例:

拿编写程序为例来说明:在一个项目中,项目经理负责前期的一些准备工作,相当于是主线程,其他开发人员负责具体的编码工作,相当于子线程,那么可以使用这个例子来模仿多线程。

1、先编写一个编码的方法:

 /// <summary>
 /// 编码的方法
 /// </summary>
 /// <param name="name">开发人员Name</param>
 /// <param name="project">负责的模块</param>
 private void Coding(string name, string project)
 {
        Console.WriteLine($")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        ;
        ; i < ; i++)
        {
             lResult += i;
        }
        //Thread.Sleep(2000);

        Console.WriteLine($")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
 }

2、启动线程

Console.WriteLine($")}】");
Console.WriteLine($")}】");
Console.WriteLine($")}】");
Task.Run(() => this.Coding("Tom", "Client"));
Task.Run(() => this.Coding("Jack", "Service"));

结果:

这时又提出了新的需求:必须所有编码工作都完成以后才能上线使用,将代码修改如下:

 Console.WriteLine($")}】");
 Console.WriteLine($")}】");
 Console.WriteLine($")}】");
 Task.Run(() => this.Coding("Tom", "Client"));
 Task.Run(() => this.Coding("Jack", "Service"));
  Console.WriteLine($")}】");

再次运行程序,效果如下:

从上面的截图中看出:这不是我们想要的效果,编码工作还没有结束就可以上线使用了,即子线程还没有结束,主线程就已经结束了。要想实现我们想要的效果,那么必须使主线程等待子线程都结束以后,主线程才能结束。这时可以使用Task提供的WaitAll()方法实现,F12查询WaitAll()方法的定义:

WaitAll()方法有很多重载,我们在这里使用第一个重载方法,即参数是Task[]数组。查看Run()方法的定义时,我们会发现Run()方法的返回值就是Task类型,那么我们可以将代码进行如下的修改:

 List<Task> taskList = new List<Task>();
 Console.WriteLine($")}】");
 Console.WriteLine($")}】");
 Console.WriteLine($")}】");
 taskList.Add( Task.Run(() => this.Coding("Tom", "Client")));
 taskList.Add( Task.Run(() => this.Coding("Jack", "Service")));
 // 等待集合中的所有线程都执行完
 Task.WaitAll(taskList.ToArray());
 Console.WriteLine($")}】");

然后运行程序,查看效果:

可以看出:这次就是我们想要的效果。但是在运行程序的时候会发现,使用了WaitAll()方法以后,界面会卡住,也就是说WaitAll()方法会阻塞当前线程,等着全部任务都执行完以后,才会进入下一行。

注意:WaitAll()除了上面使用的方法以外,还有带时间参数的重载方法,表示会等待多长时间,无论所有任务是否都完成。例如:

 List<Task> taskList = new List<Task>();
 Console.WriteLine($")}】");
 Console.WriteLine($")}】");
 Console.WriteLine($")}】");
 taskList.Add( Task.Run(() => this.Coding("Tom", "Client")));
 taskList.Add( Task.Run(() => this.Coding("Jack", "Service")));
 //限时等待,最多等待1秒
 Task.WaitAll(taskList.ToArray(), );
 Console.WriteLine("等待1s之后,执行的动作");
 // 等待集合中的所有线程都执行完
 Task.WaitAll(taskList.ToArray());
 Console.WriteLine($")}】");

效果:

这时需求又有了变化:只要其中一个模块完成,就相当于完成了里程碑的工作,这时可以用Task提供的WaitAny()方法实现。F12查询WaitAny()的定义:

WaitAny()表示等待其中任何一个任务完成就会进入下一行,代码修改如下:

 List<Task> taskList = new List<Task>();
 Console.WriteLine($")}】");
 Console.WriteLine($")}】");
 Console.WriteLine($")}】");
 taskList.Add( Task.Run(() => this.Coding("Tom", "Client")));
 taskList.Add( Task.Run(() => this.Coding("Jack", "Service")));
 Task.WaitAny(taskList.ToArray());
 Console.WriteLine($")}】");
 ////限时等待,最多等待1秒
 //Task.WaitAll(taskList.ToArray(), 1000);
 //Console.WriteLine("等待1s之后,执行的动作");
 //// 等待集合中的所有线程都执行完
 Task.WaitAll(taskList.ToArray());
 Console.WriteLine($")}】");

效果:

注意:WaitAny()同样也会阻塞当前线程,卡住界面。和WaitAll()一样,WaitAny()也有带时间参数的重载方法,表示等待多长时间。

应用场景:

1、WaitAll():假如一个界面需要的数据,来自不同的数据源,那么这时可以使用WaitAll()等待所有的数据都查询完成以后才显示界面。

2、WaitAny():商品查询,只要查询出某一个符合条件的即可。

上面讲到的WaitAll()和WaitAny()都会卡住界面,那么有没有不卡界面的方法呢?答案是肯定的:那就是WhenAll()和WhenAny().。

从上面的截图中可以看出,WhenAll()的参数还是一个Task[]类型的数组,返回值是Task类型,表示Task[]数组里面的所有任务都完成以后,创建一个新的Task。这时可以继续调用Task类提供的ContinueWith()方法。ContinueWith()方法表示Task任务完成时异步执行的延续任务。

 List<Task> taskList = new List<Task>();
 Console.WriteLine($")}】");
 Console.WriteLine($")}】");
 Console.WriteLine($")}】");
 taskList.Add(Task.Run(() => this.Coding("Tom", "Client")));
 taskList.Add(Task.Run(() => this.Coding("Jack", "Service")));

 Task.WhenAny(taskList.ToArray()).ContinueWith(t =>
 {
          Console.WriteLine($")}】");
 });

 Task.WhenAll(taskList.ToArray()).ContinueWith(t =>
 {
          Console.WriteLine($")}】");
  });

效果:

注意:

除了Task可以实现这种效果以为,TaskFactory也可以实现,例如:

 TaskFactory taskFactory = new TaskFactory();
 taskFactory.ContinueWhenAll(taskList.ToArray(), tList =>
 {
           Console.WriteLine($")}】");
 });

 taskFactory.ContinueWhenAny(taskList.ToArray(), t =>
 {
            Console.WriteLine($")}】");
 });

多线程三:Task的更多相关文章

  1. 【多线程】 Task

    [多线程] Task 一. 常用方法: 1. ContinueWith : 当前 Task 完成后, 执行传入的 Task 2. Delay : 创建一个等待的 Task,只有在调用 Wait 方法时 ...

  2. 多线程(三) java中线程的简单使用

    java中,启动线程通常是通过Thread或其子类通过调用start()方法启动. 常见使用线程有两种:实现Runnable接口和继承Thread.而继承Thread亦或使用TimerTask其底层依 ...

  3. java 多线程三

    java 多线程一 java 多线程二 java 多线程三 java 多线程四 注意到 java 多线程一 中 MyThread2 运行结果出现0.-1,那是因为在操作共享数据时没有加锁导致. 加锁的 ...

  4. 【多线程】 Task ,async ,await

    [多线程]Task ,async ,await 一. WinForm 里经常会用到多线程, 多线程的好出就不多说了,来说说多线程比较麻烦的地方 1. UI 线程与其他线程的同步,主要是 Form 和 ...

  5. 细说.NET中的多线程 (三 使用Task)

    上一节我们介绍了线程池相关的概念以及用法.我们可以发现ThreadPool. QueueUserWorkItem是一种起了线程之后就不管了的做法.但是实际应用过程,我们往往会有更多的需求,比如如果更简 ...

  6. JAVA基础知识之多线程——三种实现多线程的方法及区别

    所有JAVA线程都必须是Thread或其子类的实例. 继承Thread类创建线程 步骤如下, 定义Thead子类并实现run()方法,run()是线程执行体 创建此子类实例对象,即创建了线程对象 调用 ...

  7. Java多线程——<三>简单的线程执行:Executor

    一.概述 按照<Java多线程——<一><二>>中所讲,我们要使用线程,目前都是显示的声明Thread,并调用其start()方法.多线程并行,明显我们需要声明多个 ...

  8. 【多线程】Task

    介绍 Task是.NET推出数据任务处理的工作类.位于System.Threading.Tasks命名空间下,通过命名空间也可以看出是个多线程类. 创建Task: Task有很多构造函数,无参有参都有 ...

  9. java多线程(三)——锁机制synchronized(同步语句块)

    用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法之行一个长时间的任务,那么B线程必须等待比较长的时间,在这样的情况下可以使用synchronized同步语句快来解 ...

随机推荐

  1. js判断客户端是否是IOS系统

    在手机端应用的开发中,经常会碰到IOS系统跟Android系统去访问同一个内容时的展示效果不同,这时候我们需要区别对待,下面代码就是用js判断手机终端是否IOS系统: //判断是否为ios系统:是IO ...

  2. 华中科技大学 ubuntu14.04源

    deb http://mirrors.hust.edu.cn/ubuntu/ trusty main restricteddeb-src http://mirrors.hust.edu.cn/ubun ...

  3. unity, Collider2D.attachedRigidbody

    boss根节点上挂RigidBody2D(且boss根节点以下任何子节点均不挂RigidBody2D),boss腿部骨骼节点挂collider2D,标签为"bossLeg",bos ...

  4. C# Split() 去除 \r\n 分组

    str为读入的文本string[] ReadText = str.Replace("\r\n", "@").Split('@'); 转自 http://zhid ...

  5. Tcp超时修改

    Linux 建立 TCP 连接的超时时间分析 tags: linux | network Linux 系统默认的建立 TCP 连接的超时时间为 127 秒,对于许多客户端来说,这个时间都太长了, 特别 ...

  6. 本地搭建 Gradle 服务器,提高 Android Studio Gradle 下载速度

    AndroidStudio 更新以后,在公司网会卡在下载 Gradle 的地方,下载 Gradle 速度很慢. 看到别人的博客提供的解决办法本地搭建一个 Gradle 的服务器,然后把 Android ...

  7. Android xUtils3源代码解析之网络模块

    本文已授权微信公众号<非著名程序猿>原创首发,转载请务必注明出处. xUtils3源代码解析系列 一. Android xUtils3源代码解析之网络模块 二. Android xUtil ...

  8. 【小白的CFD之旅】21 网格划分软件的选择

    但是怎样才能获得流体计算网格呢?“工欲善其事必先利其器”,画网格该用什么器呢?小白决定找黄师姐请教一番. 小白找到黄师姐的时候,黄师姐正在电脑上忙着. “黄师姐,我发现网格划分软件有好多种,究竟哪种才 ...

  9. [PY3]——环境配置(1)——pyenv | pip | ipython | jupyter(含安装pyenv环境shell脚本)

    1.关于pyenv (1)pyenv是一个开源的.shell脚本编写的工具:Simple Python version management (2)为什么使用pyenv:当多个项目同时在开发与维护时, ...

  10. 沐雪多用户微信公众平台开发源码,商城小程序源码(2018年最新的asp.net C# 微信源码,小程序源码)

    现售价5400元,就可以搭建自己的微信平台啦 购买地址:https://item.taobao.com/item.htm?id=539102325336 该系统是由[上海沐雪网络]独家授权销售,其他地 ...