博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
菜鸟之旅——学习线程(Task)
阅读量:5908 次
发布时间:2019-06-19

本文共 4754 字,大约阅读时间需要 15 分钟。

  前面两篇回顾线程和线程池的使用方法,微软在.NET4.5推出了新的线程模型-Task。本篇将简单的介绍Task的使用方法。

Task与线程

  Task与线程或者说线程池关系紧密,可以说是基于线程池实现的,虽说任务最终还是要抛给线程去执行,但是Task仍然会比线程、线程池的开销要小,并且提供了可靠的API来控制线任务执行。

  使用Task来执行的任务最终会交给线程池来执行,若该任务需要长时间执行,可以将其标记为LongRunning,这是便会单独去请求创建线程来执行该任务。

Task

 创建

  Task的创建也存在两种方式,使用new或者使用静态工厂方式来创建:

static void Main(string[] args)        {            Task t = new Task(Menthod1);            t.Start();            Task.Factory.StartNew(Menthod2);                        Console.WriteLine("主线程的ID:{0}", Thread.CurrentThread.ManagedThreadId);            Console.WriteLine("--------------------");            Console.ReadLine();        }        static void Menthod1()        {            Thread.Sleep(2000);            Console.WriteLine("线程1的ID:{0}", Thread.CurrentThread.ManagedThreadId);            Console.WriteLine("--------------------");        }        static void Menthod2()        {            Thread.Sleep(4000);            Console.WriteLine("线程2的ID:{0}", Thread.CurrentThread.ManagedThreadId);            Console.WriteLine("--------------------");        }

  上面说到使用Task执行任务最终还是需要线程池来执行,若不想让线程池来执行,可以添加LongRunning标志:

Task t = new Task(Menthod1, TaskCreationOptions.LongRunning);        t.Start();        Task.Factory.StartNew(Menthod2, TaskCreationOptions.LongRunning);

   TaskCreationOptions还有很多枚举值,用来控制任务的更多属性。

 参数与返回值

  使用Task也可以传入参数(object类型)与返回值:

static void Main(string[] args)        {            Task.Factory.StartNew(Menthod1, 233);            //int result = Task.Factory.StartNew(new Func
(Menthod3), 233).Result; Task
t = Task.Factory.StartNew(new Func
(Menthod3), 233); int result = t.Result; Console.WriteLine("主线程的ID:{0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("result:{0}", result); Console.WriteLine("--------------------"); Console.ReadLine(); } static void Menthod1(object obj) { Thread.Sleep(2000); Console.WriteLine("线程1的ID:{0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("obj:{0}", obj); Console.WriteLine("--------------------"); } static int Menthod3(object obj) { Thread.Sleep(6000); Console.WriteLine("线程3的ID:{0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("obj:{0}", obj); Console.WriteLine("--------------------"); return obj; }

   这里为了获取返回值,阻塞了主线程,这里请注意一下。

 等待Task

  可以使用Task实例的Wait方法来实现等待任务结束,也可以向多线程一样,使用WaitAll和WaitAny一样来等待多个任务结束,不过操作更为简单:

t.Wait();        Task.WaitAll(t1, t2 ...);        Task.WaitAny(t1, t2 ...);

 

 取消Task

  任务也是可以事先取消的,不过需要使用CancellationTokenSource:

static void Main(string[] args)        {            Task.Factory.StartNew(Menthod1);            CancellationTokenSource cancelTokenSource = new CancellationTokenSource();            Task.Factory.StartNew(Menthod2, cancelTokenSource.Token);            cancelTokenSource.Cancel();            Console.WriteLine("主线程的ID:{0}", Thread.CurrentThread.ManagedThreadId);            Console.WriteLine("--------------------");            Console.ReadLine();        }

  上述代码就可以将线程2给取消掉,当然,Cancel方法可以自己找个合适的地方调用。

 

 继续Task

   在Task中,可以实现在一个任务结束后开启另一个新的任务:

static void Main(string[] args)        {            Task t = Task.Factory.StartNew(Menthod1);            t.ContinueWith(new Action
(Menthod4)); Console.WriteLine("主线程的ID:{0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("任务t的ID:{0}", t.Id); Console.WriteLine("--------------------"); Console.ReadLine(); } static void Menthod1() { Thread.Sleep(2000); Console.WriteLine("线程1的ID:{0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("--------------------"); } static void Menthod4(Task t) { Console.WriteLine("线程4的ID:{0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("任务t的ID:{0}", t.Id); Console.WriteLine("--------------------"); }

  这里因为使用了委托,也可以使用lambda表达式,更简单一些调用:

Task t = Task.Factory.StartNew(Menthod1);        t.ContinueWith(task =>        {            Console.WriteLine("线程4的ID:{0}", Thread.CurrentThread.ManagedThreadId);            Console.WriteLine("任务t的ID:{0}", task.Id);            Console.WriteLine("--------------------");        });

  

总结

  使用传统线程方式来进行多线程编程的时候,对线程的控制总是不到位,产生一些奇奇怪怪的问题;或是代码写得很杂乱;或是开发人员乱用线程,比方说无限制的创建线程、将线程池线程占满,等等。

  Task的出现,实现对传统线程操作的封装,提供可靠高效的API来控制线程,极大的方便多线程编程,所以可以用到Task的地方尽量使用Task;当然,这里仍会产生线程安全的问题,同样需要进行线程同步,与上一篇处理方式类似。

  Task的内容还有很多,更深层的运行原理、封装还等着我们去了解,现在只把我用到的东西分享出来,希望能帮助到需要的人。

  线程的学习就先告一段落了,敬请期待新的内容吧。

 

转载于:https://www.cnblogs.com/nbclw/p/8441317.html

你可能感兴趣的文章
ubuntu16.04 安装mysql 5.7
查看>>
WEBrick的使用方法
查看>>
ansible--变量
查看>>
将博客搬至51CTO
查看>>
nginx+uwsgi+django架构部署
查看>>
精通Java设计模式从初见到相爱之命令设计模式(15)
查看>>
串口异步同步通讯
查看>>
程序与生活:忘记目标你才能达到目标
查看>>
asd
查看>>
MySQL数据库性能优化的实际操作方案
查看>>
idea generate persistence mapping 生成dao bean实例
查看>>
linux sar命令详解
查看>>
阿里云提示ecshop Discuz uc.key泄露导致代码注入漏洞修复
查看>>
关于STUN和NAT
查看>>
常见JVM内存异常分析
查看>>
针对不同浏览器内核css写法
查看>>
ubuntu下添加gimp的ppa
查看>>
使用Java8实现自己的个性化搜索引擎
查看>>
龙家贰少的MarkDown学习笔记
查看>>
查看端口占用命令
查看>>