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. 3dmax,查看场景中所有材质

  2. Eclipse_Configure

    原文链接:http://android.eoe.cn/topic/android_sdk 1. 下载Eclipse 在前面我们配置好了JDK环境后,就可以开始配置Android的集成开发环境了,官方G ...

  3. Error:Cause: org/gradle/api/publication/maven/internal/DefaultMavenFactory Android

    首先,要看一下自己的项目使用 “Gradle版本” 接着要看一下项目根目录的build.gradle文件中的“dependencies”的 classpath 'com.github.dcendent ...

  4. zabbix 实现对服务器的负载监控

    # grep Include /etc/zabbix/zabbix_agentd.conf ### Option: Include # Include= Include=/etc/zabbix/zab ...

  5. Win7 下面升级VS2017 vs_community install Microsoft.Windows.D3DCompiler.Msu.Win7

    因为.NET Framework 4.7 WPF 功能采用D3DCompiler_47.dll依赖项.默认情况下,此 D3DCompiler_47.dll 并不是存在于 Windows 7 SP1,W ...

  6. (原创)c++11改进我们的模式之改进单例模式

    我会写关于c++11的一个系列的文章,会讲到如何使用c++11改进我们的程序,本次讲如何改进我们的模式,会讲到如何改进单例模式.观察者模式.访问者模式.工厂模式.命令模式等模式.通过c++11的改进, ...

  7. 每日英语:The Risks of Big Data for Companies

    Big data. It's the latest IT buzzword, and it isn't hard to see why. The ability to parse more infor ...

  8. Android 支付宝接口调用

    在近期,公司需要开发一个关于在线支付的模块,所以需要用到第三方支付平台 转载请注明出处:http://blog.csdn.net/ht_android/article/details/45307165 ...

  9. [mBean]-Delphi框架,回归简单,自然。

    [mBean]的萌芽 最近公司要求把我们公司的任务可以外包,问我有没有好的方案. 如果要其他程序员的人来做我们内部的框架会导致了,内部的框架需要公布很多单元和逻辑,思路.其次要把我们的思路和规则强加给 ...

  10. 通过kafka提供的命令来查看offset消费情况

    使用kafka的bin目录下面的kafka-consumer-groups.sh命令可以查看offset消费情况,注意,如果你的offset是存在kafka集群上的,就指定kafka服务器的地址boo ...