线程 线程池 Task
2018-06-24 00:10:17来源:未知 阅读 ()
首先声明 这是读了 愉悦的绅士 文章
《菜鸟之旅——学习线程(线程和线程池)》
《Task与线程》
的一些个人总结,还是那句话,如有不对,欢迎指正
文章以代码加注释的方法展示。
//线程的创建,阻塞和同步
public static ManualResetEvent MREstop=new ManualResetEvent(false); public static AutoResetEvent AREstop = new AutoResetEvent(false); static void Main(string[] args) { //使用方法注册 Thread Thread1 = new Thread(Method1); //使用Lambda注册 Thread Thread2 = new Thread((s) => { //暂停线程2,使用ManualResetEvent暂停,当使用Set方法的时候会跳过所有WaitOne(); //MREstop.WaitOne(); //暂停主线程,使用AutoResetEvent暂停,当使用Set方法的时候会跳过第一次遇到的WaitOne(); AREstop.WaitOne(); Console.WriteLine("----这是带参数方法2,参数为{0}----",s); Console.WriteLine(DateTime.Now); Console.WriteLine("----方法2结束----"); }); //若直接运行,会发现,Thread1和主线程的代码会交错在一起,而Thread2的代码一直在最后出现,这是因为Thread1和主线程一起运行,而Thread2延迟运行 Thread1.Start(); Thread2.Start("这是一个参数"); //取消注释,会发现Thread1和Thread2都执行完后,才会执行主线程代码 //Thread1.Join(); //Thread2.Join(); //暂停主线程,使用ManualResetEvent暂停,当使用Set方法的时候会跳过所有WaitOne(); //MREstop.WaitOne(); //暂停主线程,使用AutoResetEvent暂停,当使用Set方法的时候会跳过第一次遇到的WaitOne(); //AREstop.WaitOne(); Console.WriteLine("----这是主线程----"); Console.WriteLine(DateTime.Now); Console.WriteLine("----主线程结束----"); } static void Method1() { Thread.Sleep(1000); Console.WriteLine("----这是不带参数方法1----"); Console.WriteLine(DateTime.Now); Console.WriteLine("----方法1结束----"); //使用线程1开启同步,当使用Set方法的时候会跳过所有WaitOne(); //MREstop.Set(); //使用线程1开启同步,,当使用Set方法的时候会跳过第一次遇到的WaitOne(),所以主要是看Cpu先执行那个进程; //AREstop.Set(); }
//对方法加锁
static readonly object LockObject = new object(); static int i = 100; static void Main(string[] args) { //实例化100条线程,执行同一个方法 for (int i = 0; i < 100; i++) { Thread Thread1 = new Thread(Method1); Thread1.Start(); } } static void Method1() { //若不加锁,所有线程都可以同时访问该方法,会造成显示的结果混乱,而加了锁,就同时只能拥有一个线程访问该方法 //Monitor.Enter(LockObject); //i++非原子性操作,可能同时被多个线程执行,造成竞态,会影响运算结果,所以不能在多线程中使用。 //i++; //推荐使用线程原子性自增操作 System.Threading.Interlocked.Increment(ref i); Thread.Sleep(10); Console.WriteLine("This is Thread{0} and i={1}", Thread.CurrentThread.ManagedThreadId, i); Console.WriteLine("--------------------------------"); //加了锁必须解锁 //Monitor.Exit(LockObject); //或者使用lock(LockObject)的方法,相当于try{Monitor.Enter(LockObject);}catch{}finally{Monitor.Exit(LockObject);}的简便写法 //lock(LockObject) //{ // System.Threading.Interlocked.Increment(ref i); // Thread.Sleep(10); // Console.WriteLine("This is Thread{0} and i={1}", Thread.CurrentThread.ManagedThreadId, i); // Console.WriteLine("--------------------------------"); //} }
//线程池
public static AutoResetEvent AREstop1 = new AutoResetEvent(false); static void Main(string[] args) { AutoResetEvent AREstop2 = new AutoResetEvent(false); //创建并且执行,线程池上限为CPU核心数*250,默认为后台线程 ThreadPool.QueueUserWorkItem(new WaitCallback(Method1), AREstop2); //创建并且执行 ThreadPool.QueueUserWorkItem(new WaitCallback(s => { Thread.Sleep(2000); Console.WriteLine("----这是带参数方法2,参数为{0}----", s); Console.WriteLine(DateTime.Now); Console.WriteLine("----方法2结束----"); AREstop1.Set(); }), "这是一个参数"); //线程池的同步线程和线程一致,可以使用ManualResetEvent和AutoResetEvent执行。 //由于线程池没有Join方法,所以可以使用WaitAll()方法来达到所有线程执行完毕后执行主线程的效果 List<WaitHandle> handles = new List<WaitHandle>(); handles.Add(AREstop1); // handles.Add(AREstop2); //注意,对多个线程要使用不同的AutoResetEvent,只要数组中的AutoResetEvent接受到set指令就解锁,若全部为同一个名字 //则只要任何一个进程set之后,就会执行主线程。由于线程池默认为后台线程,一旦执行完成主线程,则其余线程自动结束 //必须数组之中的AutoResetEvent全部set后才会执行,如果该有一个没有set,都不会执行主线程。 //WaitAll最大数组上限为64 WaitHandle.WaitAll(handles.ToArray()); Console.WriteLine("----这是主线程----"); Console.WriteLine(DateTime.Now); Console.WriteLine("----主线程结束----"); } //方法要带一个参数 static void Method1(object obj) { Thread.Sleep(1000); Console.WriteLine("----这是带参数方法1----"); Console.WriteLine(DateTime.Now); Console.WriteLine("----方法1结束----"); AutoResetEvent AREstop2 = (AutoResetEvent)obj ; AREstop2.Set(); }
//Task 任务 推荐使用任务来做多线程的,便于管理
public static AutoResetEvent AREstop1 = new AutoResetEvent(false); static void Main(string[] args) { //Task实例化的都是后台线程,如果要更改为前台线程,需要再方法里面修改 #region Task任务 使用线程池 //{ // //实例化任务,必须手动启动,注意,方法是不能带参数的 // Task TaskFirst = new Task(Method1); // //Status可以标识当前任务的状态 // //Created:表示默认初始化任务,但是“工厂创建的”实例直接跳过。 // //WaitingToRun: 这种状态表示等待任务调度器分配线程给任务执行。 // //RanToCompletion:任务执行完毕。 // Console.WriteLine("TaskFirst的状态:{0}", TaskFirst.Status); // TaskFirst.Start(); // Console.WriteLine("TaskFirst的状态:{0}", TaskFirst.Status); // //工厂创建的直接执行 // Task TaskSecond = Task.Factory.StartNew(() => // { // Console.WriteLine("----这是不带参数方法2----"); // Console.WriteLine(DateTime.Now); // Console.WriteLine("----方法2结束----"); // }); // //使用这种方法删除任务 // //CancellationTokenSource cancelTokenSource = new CancellationTokenSource(); // //Task.Factory.StartNew(() => // //{ // // Console.WriteLine("----这是要删除方法4----"); // // Console.WriteLine(DateTime.Now); // // Console.WriteLine("----要删除方法结束----"); // //}, cancelTokenSource.Token); // //cancelTokenSource.Cancel(); // //流程控制 // { // //没有加标识的默认使用线程池创建,若主线程结束自动结束,所以需要先堵塞主线程 // //AREstop1.WaitOne(); // //或者使用阻塞 // Task.WaitAll(TaskFirst, TaskSecond); // //也可以使用Wait()等待单个线程,你会发现下面TaskFirst的状态的状态为Running,因为主线程开始运行了,而线程TaskFirst还在运行中 // //TaskSecond.Wait(); // //Task.WaitAny 只要数组中有一个执行完毕,就继续执行主线程 // //Task.WaitAny(TaskFirst, TaskSecond); // //继续执行,在TaskFirst任务结束后继续执行,此时TaskFirst已经结束。记得加Wait(),否则主线程结束就直接结束了。 // TaskFirst.ContinueWith(NewTask => // { // Console.WriteLine("----这是不带参数方法3----"); // Console.WriteLine(DateTime.Now); // Console.WriteLine("TaskFirst的状态:{0}", TaskFirst.Status); // Console.WriteLine("----方法3结束----"); // }).Wait(); // } // Console.WriteLine("TaskFirst的状态:{0}", TaskFirst.Status); //} #endregion #region Task任务 使用线程 { ////实例化任务,必须手动启动,注意,方法是不能带参数的 //Task TaskFirst = new Task(Method1, TaskCreationOptions.LongRunning); //TaskFirst.Start(); } #endregion #region Task任务 带参数 { Task<int> TaskFirst = new Task<int>(((x) => { return (int)(x); }), 10); TaskFirst.Start(); Console.WriteLine(" result ={0}", TaskFirst.Result); Task<string> TaskSecond = Task<string>.Factory.StartNew(new Func<object, string>(x => { return $"This is {x}"; }), 10); Console.WriteLine(" result ={0}", TaskSecond.Result); } #endregion Console.WriteLine("----这是主线程----"); Console.WriteLine(DateTime.Now); Console.WriteLine("----主线程结束----"); } //C# 6.0只读赋值 static object Locker { get; } = new object(); static void Method1() { lock (Locker) { Thread.CurrentThread.IsBackground = false; Thread.Sleep(1000); Console.WriteLine("----这是带参数方法1----"); Console.WriteLine(DateTime.Now); Console.WriteLine("----方法1结束----"); //AREstop1.Set(); } }
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:里氏转换
- css 元素实际宽高 2019-09-17
- vue项目中兼容ie8以上浏览器的配置 2019-08-14
- 默认文档解析--手机web app开发笔记(二) 2019-08-14
- 学WEB前端,学历到底重不重要 2019-05-08
- 小tips:使用rem+vw实现简单的移动端适配 2019-03-06
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash