線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以並發多個線程,每條線程並行執行不同的任務。
一.通過委托的方式
委托中的Invoke方法完成一個委托方法的封送,在Invoke封送的方法被執行完畢前,Invoke方法不會返回,從而調用者線程將被阻塞。委托中的BeginInvoke方法是從ThreadPool取出一個線程來執行這個方法,以獲得異步執行效果的。
public delegate int AddDelegate(int a, int b); //定義一個委托對象 static void Main(string[] args) { Console.WriteLine("start"); AddDelegate d1 = Add; //異步回調方法,異步方法執行完可以選擇執行這個方法 AsyncCallback cab = t => { //Console.WriteLine(d1.EndInvoke(t)); Console.WriteLine(t.AsyncState); //可以獲取傳遞過來的參數 Console.WriteLine(t.IsCompleted); }; IAsyncResult ar = d1.BeginInvoke(5,2,cab,12); //前兩個參數為引用方法傳遞的參數,cab為上面的回調方法,12為回調方法中的參數,執行BeginInvoke會返回一個IAsyncResult對象 Thread.Sleep(2000); int result = d1.EndInvoke(ar); //該方法返回委方法中的真正返回值,該方法會阻塞主線程一直到異步執行完,EndInvoke只能被執行一次 Console.WriteLine("結果:"+result); } public static int Add(int a,int b) { return a + b; }
二.通過Thread類
C#中的Thread類主要提供四個構造方法,ThreadStart是一個無參的委托,意味着我們能傳遞一個無參的方法進去。ParameterizedThreadStart是一個只有一個參數,參數類型為object的委托,我們可以傳一個一個參數,參數類型為object的類型進去
static void Main(string[] args) { //ThreadStart start1 = AddNoParms; //Thread thread1 = new Thread(start1); Thread thread1 = new Thread(AddNoParms); //簡化寫法,直接傳遞與委托方法簽名對應的方法 Thread thread2 = new Thread(AddHasParms); //有參的形式 thread1.Start();//開啟這個線程 thread2.Start("thread2"); //開啟有參的Thread線程 thread1.Name = "thread1"; //獲取或設置線程的名稱。 thread1.IsBackground = true; //獲取或設置一個值,該值指示某個線程是否為后台線程。 Thread.Sleep(2000); //讓線程暫停一段時間。 thread1.Abort(); //銷毀線程 Console.WriteLine(thread1.IsAlive); //獲取線程狀態 //獲取異步回調的返回值 int returndata = 0; //聲明一個變量用來接收異步方法執行的返回值 ThreadStart threadstart = new ThreadStart (() =>{ returndata = Add(1, 2); AddNoParms(); }); Thread thread3 = new Thread(threadstart); thread3.Start(); Console.WriteLine(returndata); } public static void AddHasParms(object str) { Console.WriteLine(str); } public static void AddNoParms() { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Console.WriteLine("add"); } public static int Add(int a,int b) { return a + b; }
Thread類中還提供了許多屬性和方法供我們使用
//屬性 IsAlive //獲取一個值,該值指示當前線程的執行狀態。 IsBackground //獲取或設置一個值,該值指示某個線程是否為后台線程。前台進程跟后台進程的區別:程序關閉時,后台線程直接關閉,但前台線程會執行完后關閉。通過Thread類新建線程默認為前台線程。其他方式創建的都是后台線程。 IsThreadPoolThread //獲取一個值,該值指示線程是否屬於托管線程池。 Priority //獲取或設置一個值,該值指示線程的調度優先級。 //方法 Abort //在調用此方法的線程上引發 ThreadAbortException,以開始終止此線程的過程。調用此方法通常會終止線程。 Join //阻塞調用線程,直到某個線程終止為止。此方法有不同的重載形式 ResetAbort //取消為當前線程請求的 Abort。
三.ThreadPool
ThreadPool類會在線程的托管池中重用已有的線程,一個應用程序最多只能有一個線程池,可以通過QueueUserWorkItem方法將工作函數排入進程池。QueueUserWorkItem有兩個構造函數,WaitCallback是一個只有一個參數,參數類型為object的委托,我們可以傳一個參數,參數類型為object的對象進行實例化
static void Main(string[] args) {
ThreadPool.SetMinThreads(1,1);
ThreadPool.SetMaxThreads(1,5); //調用方式一 用WaitCallback這個委托進行實例化 WaitCallback waitCallback = new WaitCallback(AddHasParms); ThreadPool.QueueUserWorkItem(waitCallback, "helloworld"); //調用方式二 傳遞與WaitCallback對應的方法進行實例化 ThreadPool.QueueUserWorkItem(AddHasParms,"helloworld"); //調用方法三 通過WaitCallback相對應的匿名方法,在匿名方法中進行調用 ThreadPool.QueueUserWorkItem(n=> { AddNoParms(); AddHasParms("helloworld"); }); } public static void AddHasParms(object str) { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Console.WriteLine(str); } public static void AddNoParms() { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); }
四.Task
static void Main(string[] args) { //方式一 無返回值時 Task task1 = new Task(AddHasParms, "helloworld"); task1.Start(); Task.WaitAll(task1); //等待所有任務結束 //有返回值時 Task<int> task2 = new Task<int>(Add, "obj"); task2.Start(); Console.WriteLine(task2.Result); //打印返回值 //方式二 通過Run方法創建 無返回值 Task.Run(() => AddHasParms("hello")); //無返回值時 Task<int> task3 = Task.Run(() => Add("obj")); Console.WriteLine(task3.Result); //方式三 無返回值時 Task.Factory.StartNew(() => AddHasParms("helloworld")); Task.WaitAll(); //有返回值時 var task4=Task.Factory.StartNew(() => Add("obj")); Console.WriteLine(task4.Result); } public static void AddHasParms(object str) { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Console.WriteLine(str); } public static int Add(object a) { return 1; }