1.Thread
詳細介紹:https://www.cnblogs.com/cheng8/p/16147918.html
使用Thread類通過ThreadStart(無參數)或ParameterizedThreadStart(一個輸入參數)類型的委托創建一個Thread對象,開啟一個新線程,執行該委托傳遞的任務,此時線程尚未處於運行狀態。調用Start()函數啟動線程,當前線程繼續執行。調用Join()函數可以阻塞當前線程,直到調用Join()的線程終止。
Thread類創建的線程默認為前台線程,可以通過IsBackground屬性設置其為前台或后台線程。還可以通過Priority屬性設置線程的優先級。
如需中止線程,調用Abort()方法,在調用該方法的線程上拋出ThreadAbortException異常,以結束該線程。線程內部可以通過try catch捕獲該異常,在catch模塊中進行一些必要的處理,如釋放持有的鎖和文件資源等,還可以通過Thread.ResetAbort()方法阻止線程的中止。但是通常來說,應當慎重使用Abort()方法,如果在當前線程中拋出該異常,其結果是可預測的,但是對於其他線程,它會中斷任何正在執行的代碼,有可能中斷靜態對象的生成,造成不可預測的結果。
Thread thread = new Thread(() => { Console.WriteLine("Hello"); }); thread.Start(); Console.ReadKey();
2.線程池
但是線程池的使用也有一些限制:
- 線程池中的線程均為后台線程,並且不能修改為前台線程
- 不能給入池的線程設置優先級或名稱
- 對於COM對象,入池的所有線程都是多線程單元(MTA)線程,許多COM對象都需要單線程單元(STA) 線程
- 入池的線程只適合時間較短的任務,如果線程需要長時間運行,應使用Thread類創建線程或使用Task的LongRunning選項
for (int i = 0; i < 5; ++i) ThreadPool.QueueUserWorkItem(Do); Console.ReadKey(); static void Do(Object o) { for (int i = 0; i < 3; i++) Console.WriteLine("loop:{0}, thread id: {1}", i, Thread.CurrentThread.ManagedThreadId); }
3.Parallel類
Parallel和Task類都位於System.Threading.Task命名空間中,是對Thread和ThreadPool類更高級的抽象。Parrallel類有For()、ForEach()、Invoke()三個方法,前兩者在每次迭代中調用相同的代碼,實現了數據並行性,Invoke()允許同時調用不同的方法,實現任務並行性。
For()和ForEach()兩者的用法類似。如下例,調用Parallel.For()方法,實現從0到10的迭代,每次迭代是並行執行的,並且從輸出結果可以看出,執行順序是不能保證的。
ParallelLoopResult result = Parallel.For(0, 10, i => { Console.WriteLine("i:{0}, thread id: {1}", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(10); }); Console.WriteLine("Is completed: {0}", result.IsCompleted); Console.ReadKey();
通過ParallelLoopState的Break()或Stop()方法,可以提前中斷Parallel.For()的迭代。
ParallelLoopResult result = Parallel.For(0, 100, (i, state) => { Console.WriteLine("i:{0}, thread id: {1}", i, Thread.CurrentThread.ManagedThreadId); if (i > 10) state.Break(); Thread.Sleep(10); }); Console.WriteLine("Is completed: {0}", result.IsCompleted); Console.WriteLine("Lowest break iteration: {0}", result.LowestBreakIteration); Console.ReadKey();
如需同時執行多個不同的任務,可以使用Parallel.Invoke()方法,它允許傳遞一個Action委托數組。
Parallel.Invoke(Func1, Func2, Func3);
4.Task類
啟動任務
TaskFactory tf = new TaskFactory(); Task t1 = tf.StartNew(TaskMethod.DoTask, "using a task factory"); Task t2 = Task.Factory.StartNew(TaskMethod.DoTask, "factory via a task"); Task t3 = new Task(TaskMethod.DoTask, "using a task constructor and start"); t3.Start(); var t4 = Task.Run(() => TaskMethod.DoTask("using Run method")); Console.ReadKey(); class TaskMethod { static object taskLock = new object(); public static void DoTask(object msg) { lock (taskLock) { Console.WriteLine(msg); Console.WriteLine("Task id:{0}, Thread id :{1}", Task.CurrentId == null ? "no task" : Task.CurrentId.ToString(), Thread.CurrentThread.ManagedThreadId); } } }
接收任務的返回值
對於任務有返回值的情況,可使用Task<TResult>泛型類,TResult定義了返回值的類型,以下代碼演示了調用返回int值的任務的方法。
var t5 = new Task<int>(TaskWithResult, Tuple.Create<int, int>(1, 2)); t5.Start(); t5.Wait(); Console.WriteLine("adder results: {0}", t5.Result); Console.ReadKey(); static int TaskWithResult(object o) { Tuple<int, int> adder = (Tuple<int, int>)o; return adder.Item1 + adder.Item2; }
同步調用
調用Task類的RunSynchronously()方法,可以實現同步調用,直接在當前線程上調用該任務。
TaskMethod.DoTask("Just Main thread"); Task t1 = new Task(TaskMethod.DoTask, "using Run Sync"); t1.RunSynchronously(); class TaskMethod { static object taskLock = new object(); public static void DoTask(object msg) { lock (taskLock) { Console.WriteLine(msg); Console.WriteLine("Task id:{0}, Thread id :{1}", Task.CurrentId == null ? "no task" : Task.CurrentId.ToString(), Thread.CurrentThread.ManagedThreadId); } } }
指定連續任務
TaskFactory tf = new TaskFactory(); Task t1 = tf.StartNew(() => { Console.WriteLine("Current Task id = {0}", Task.CurrentId); Console.WriteLine("執行任務1\r\n"); Thread.Sleep(10); }); Task t2 = t1.ContinueWith((t) => { Console.WriteLine("Last Task id = {0}", t.Id); Console.WriteLine("Current Task id = {0}", Task.CurrentId); Console.WriteLine("執行任務2\r\n"); Thread.Sleep(10); }); Task t3 = t2.ContinueWith(delegate (Task t) { Console.WriteLine("Last Task id = {0}", t.Id); Console.WriteLine("Current Task id = {0}", Task.CurrentId); Console.WriteLine("執行任務3\r\n"); }, TaskContinuationOptions.OnlyOnRanToCompletion); Console.ReadKey();
var backgroundScheduler = TaskScheduler.Default; var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task.Factory.StartNew(delegate { DoBackgroundComputation(); }, backgroundScheduler). ContinueWith(delegate { UpdateUI(); }, uiScheduler). ContinueWith(delegate { DoAnotherBackgroundComputation(); }, backgroundScheduler). ContinueWith(delegate { UpdateUIAgain(); }, uiScheduler);