有严格时间、先后顺序限制的只能使用单线程;可以独立并发执行的就可以使用多线程
一、Thread(.NetFramework 1.0)
优点:API丰富,可执行的操作多
缺点:1、Thread线程虽然可执行的操作多,但是响应并不灵敏(因为具体的线程分配要CPU决定),所以可能达不到想要的效果。
2、Thread线程启动是没有控制的(如果实例化了一百万个线程是真的会调用一百万个线程),所以可能会导致死机。
-
- Thread thread = new Thread((a) => { Console.WriteLine("asdf"+a); });
- thread.Start(6);
常用api
- 开启一个新线程
- thread.Start();
-
- 线程挂起,已经过期的方法
- //thread.Suspend();
- //thread.Resume();//线程恢复,已经过期的方法
-
- 终结线程,抛出一个异常
- thread.Abort();
- 把终结的线程再次启动,会有延时
- Thread.ResetAbort();
-
- 设置优先级,不能保证一定会优先执行,只是提升概率
- thread.Priority = ThreadPriority.Highest;
-
- 为后台线程,线程随进程结束而结束
- thread.IsBackground = true;
-
- 前台线程,进程结束后,任务执行完毕以后线程才结束
- thread.IsBackground = false;
-
- 线程等待
- 1 ThreadState判断
- while (thread.ThreadState!=ThreadState.Stopped)
- {
- Thread.Sleep(200);
- }
-
- 2 Join等待
- thread.Join();//等待线程结束
- thread.Join(200);//限时等待,最多等待200ms,超时就不等了
二、ThreadPool (.NetFrameWork 2.0)
优点:使用池化资源管理设计思想。线程是一种资源,要使用线程就去申请一个线程,使用之后就释放掉;池化就是做了一个容器,容器提前申请线程,程序要使用线程就直接找容器获取,用完再放回容器,避免频繁的申请和销毁;容器自己还会根据限制的数量去申请和释放。
缺点:API太少了,在线程等待顺序控制特别弱(MRE解决)
- WaitCallback callback1 = o => { Console.WriteLine("dfhj"); }; //不带参数
- ThreadPool.QueueUserWorkItem(callback1);
- WaitCallback callback2 = o => { Console.WriteLine("dfhj"+o); };//带参数
- ThreadPool.QueueUserWorkItem(callback2,"wh");
三、Task(.NetFramework 3.0)多线程的最佳实践
优点:1、使用了线程池的
2、API特别多
task.start()
- Action action = () => { Console.WriteLine("hello,world"); };
- Task task = new Task(action);
- task.Start();
task.run()
带参
- tasks.Add(Task.Run(()=> { Test("hello,word"); })); //带参
-
-
- //委托调用的函数
- public void Test(string i)
- {
- Thread.Sleep(5000);
- Console.WriteLine(i);
- }
无参
- tasks.Add(Task.Run(()=> { Test(); })); //带参
-
-
- //委托调用的函数
- public void Test()
- {
- Thread.Sleep(5000);
- Console.WriteLine("hello word");
- }
Task.WaitAll 此方法需要传进一个线程数组。数组里的线程执行过程中,会阻塞主线程。
Task.WaitAny 当数组中的任意一个线程完成后就会继续往下执行
- Console.WriteLine("主线程");
- List
tasks = new List(); - tasks.Add(Task.Run(()=> { Test(1); }));
- tasks.Add(Task.Run(() => { Test(2); }));
- tasks.Add(Task.Run(() => { Test(3); }));
- tasks.Add(Task.Run(() => { Test(4); }));
- tasks.Add(Task.Run(() => { Test(5); }));
- Task.WaitAny(tasks.ToArray());
- Console.WriteLine("程序1/5");
- Task.WaitAll(tasks.ToArray());
- Console.WriteLine("程序完成");
但是当阻塞线程的时候,主线程会卡住。为了避免主线程卡住,可以选择用TaskFactory.ContinueWhenAll的方式解决(括号里第一个参数是要执行的线程数组,第二个参数是执行完线程数组之后要执行函数的委托(类似与BeginInvoke的第二个参数))
- List
tasks = new List(); - tasks.Add(Task.Run(()=> { Test(1); }));
- tasks.Add(Task.Run(() => { Test2(2); }));
- tasks.Add(Task.Run(() => { Test(3); }));
- tasks.Add(Task.Run(() => { Test(4); }));
- tasks.Add(Task.Run(() => { Test(5); }));
- TaskFactory taskFactory = new TaskFactory();
- taskFactory.ContinueWhenAny(tasks.ToArray(), tArray => { Console.WriteLine("程序完成1/5"); });
- taskFactory.ContinueWhenAll(tasks.ToArray(), tArray => { Console.WriteLine("程序完成"); });
四、Parallel(并行编程)
Parallel可以启动多线程,但是主线程也参与计算(其他异步线程调用时候主线程闲着啥也不干,使用Parallel主线程也产于计算所以可以少申请一个线程),故卡界面。
- Parallel.Invoke(
-
- () => { Thread.Sleep(2000); Console.WriteLine("hello,world1"); },
- () => { Thread.Sleep(2000); Console.WriteLine("hello,world2"); },
- () => { Thread.Sleep(2000); Console.WriteLine("hello,world3"); },
- () => { Thread.Sleep(2000); Console.WriteLine("hello,world4"); }
-
- );
可以通过ParallelOption轻松控制最大并发数量。