Thread类(线程)
操作系統(tǒng)通過(guò)線程對(duì)程序的執(zhí)行進(jìn)行管理,當(dāng)操作系統(tǒng)運(yùn)行一個(gè)程序的時(shí)候,首先,操作系統(tǒng)將為這個(gè)準(zhǔn)備運(yùn)行的程序分配一個(gè)進(jìn)程,以管理這個(gè)程序所需要的各種資源。在這些資源之中,會(huì)包含一個(gè)稱為主線程的線程數(shù)據(jù)結(jié)構(gòu),用來(lái)管理這個(gè)程序的執(zhí)行狀態(tài)。
在Windows操作系統(tǒng)下,線程的的數(shù)據(jù)結(jié)構(gòu)包含以下內(nèi)容:
1、線程的核心對(duì)象:主要包含線程當(dāng)前的寄存器狀態(tài),當(dāng)操作系統(tǒng)調(diào)度這個(gè)線程開(kāi)始運(yùn)行的時(shí)候,寄存器的狀態(tài)將被加載到CPU中,重新構(gòu)建線程的執(zhí)行環(huán)境,當(dāng)線程被調(diào)度出來(lái)的時(shí)候,最后的寄存器狀態(tài)被重新保存到這里,已備下一次執(zhí)行的時(shí)候使用。
2、線程環(huán)境塊(Thread Environment Block,TED):是一塊用戶模式下的內(nèi)存,包含線程的異常處理鏈的頭部。另外,線程的局部存儲(chǔ)數(shù)據(jù)(Thread Local Storage Data)也存在這里。
3、用戶模式的堆棧:用戶程序的局部變量和參數(shù)傳遞所使用的堆棧,默認(rèn)情況下,Windows將會(huì)被分配1M的空間用于用戶模式堆棧。
4、內(nèi)核模式堆棧:用于訪問(wèn)操作系統(tǒng)時(shí)使用的堆棧。
在搶先式多任務(wù)的環(huán)境下,在一個(gè)特定的時(shí)間,CPU將一個(gè)線程調(diào)度進(jìn)CPU中執(zhí)行,這個(gè)線程最多將會(huì)運(yùn)行一個(gè)時(shí)間片的時(shí)間長(zhǎng)度,當(dāng)時(shí)間片到期之后,操作系統(tǒng)將這個(gè)線程調(diào)度出CPU,將另外一個(gè)線程調(diào)度進(jìn)CPU,我們通常稱這種操作為上下文切換。
在每一次的上下文切換時(shí),Windows將執(zhí)行下面的步驟:
- 將當(dāng)前的CPU寄存器的值保存到當(dāng)前運(yùn)行的線程數(shù)據(jù)結(jié)構(gòu)中,即其中的線程核心對(duì)象中。
- 選中下一個(gè)準(zhǔn)備運(yùn)行的線程,如果這個(gè)線程處于不同的進(jìn)程中,那么,還必須首先切換虛擬地址空間。
- 加載準(zhǔn)備運(yùn)行線程的CPU寄存器狀態(tài)到CPU中。
公共語(yǔ)言運(yùn)行時(shí)CLR(Common Language Runtime)是.Net程序運(yùn)行的環(huán)境,它負(fù)責(zé)資源管理,并保證應(yīng)用和底層操作系統(tǒng)之間必要的分離。
在.Net環(huán)境下,CLR中的線程需要通過(guò)操作系統(tǒng)的線程完成實(shí)際的工作,目前情況下,.Net直接將CLR中的線程映射到操作系統(tǒng)的線程進(jìn)行處理和調(diào)度,所以,我們每創(chuàng)建一個(gè)線程將會(huì)消耗1M以上的內(nèi)存空間。但未來(lái)CLR中的線程并不一定與操作系統(tǒng)中的線程完全對(duì)應(yīng)。通過(guò)創(chuàng)建CLR環(huán)境下的邏輯線程,我們可能創(chuàng)建更加節(jié)省資源的線程,使得大量的CLR線程可以工作在少量的操作系統(tǒng)線程之上。
?
1. System.Threading.Thread類
System.Threading.Thread是用于控制線程的基礎(chǔ)類,通過(guò)Thread可以控制當(dāng)前應(yīng)用程序域中線程的創(chuàng)建、掛起、停止、銷毀。
它包括以下常用公共屬性:
| CurrentContext | 獲取線程正在其中執(zhí)行的當(dāng)前上下文。 |
| CurrentThread | 獲取當(dāng)前正在運(yùn)行的線程。 |
| ExecutionContext | 獲取一個(gè) ExecutionContext 對(duì)象,該對(duì)象包含有關(guān)當(dāng)前線程的各種上下文的信息。 |
| IsAlive | 獲取一個(gè)值,該值指示當(dāng)前線程的執(zhí)行狀態(tài)。 |
| IsBackground | 獲取或設(shè)置一個(gè)值,該值指示某個(gè)線程是否為后臺(tái)線程。 |
| IsThreadPoolThread | 獲取一個(gè)值,該值指示線程是否屬于托管線程池。 |
| ManagedThreadId | 獲取當(dāng)前托管線程的唯一標(biāo)識(shí)符。 |
| Name | 獲取或設(shè)置線程的名稱。 |
| Priority | 獲取或設(shè)置一個(gè)值,該值指示線程的調(diào)度優(yōu)先級(jí)。 |
| ThreadState | 獲取一個(gè)值,該值包含當(dāng)前線程的狀態(tài)。 |
?常用屬性示例:
using System; using System.Threading;namespace ConsoleApp {class Program{static void Main(string[] args){//新建3個(gè)線程并設(shè)定各自的優(yōu)先級(jí)Thread t1 = new Thread(Run);t1.Priority = ThreadPriority.Normal;t1.Start();Console.ReadKey();}public static void Run(){Thread t1 = Thread.CurrentThread; //靜態(tài)屬性,獲取當(dāng)前執(zhí)行這行代碼的線程Console.WriteLine("我的優(yōu)先級(jí)是:" + t1.Priority);Console.WriteLine("我是否還在執(zhí)行:" + t1.IsAlive);Console.WriteLine("是否是后臺(tái)線程:" + t1.IsBackground);Console.WriteLine("是否是線程池線程:" + t1.IsThreadPoolThread);Console.WriteLine("線程唯一標(biāo)識(shí)符:" + t1.ManagedThreadId);Console.WriteLine("我的名稱是:" + t1.Name);Console.WriteLine("我的狀態(tài)是:" + t1.ThreadState);}} } View Code?
2. 線程的標(biāo)識(shí)符
ManagedThreadId是確認(rèn)線程的唯一標(biāo)識(shí)符,程序在大部分情況下都是通過(guò)Thread.ManagedThreadId來(lái)辨別線程的。而Name是一個(gè)可變值,在默認(rèn)時(shí)候,Name為一個(gè)空值 Null,開(kāi)發(fā)人員可以通過(guò)程序設(shè)置線程的名稱,但這只是一個(gè)輔助功能。
?
3. 線程的優(yōu)先級(jí)別
.NET為線程設(shè)置了Priority屬性來(lái)定義線程執(zhí)行的優(yōu)先級(jí)別,里面包含5個(gè)選項(xiàng),其中Normal是默認(rèn)值。除非系統(tǒng)有特殊要求,否則不應(yīng)該隨便設(shè)置線程的優(yōu)先級(jí)別。
| Lowest | 可以將 Thread 安排在具有任何其他優(yōu)先級(jí)的線程之后。 |
| BelowNormal | 可以將 Thread 安排在具有?Normal?優(yōu)先級(jí)的線程之后,在具有?Lowest?優(yōu)先級(jí)的線程之前。 |
| Normal | 默認(rèn)選擇??梢詫?Thread 安排在具有?AboveNormal?優(yōu)先級(jí)的線程之后,在具有BelowNormal?優(yōu)先級(jí)的線程之前。 |
| AboveNormal | 可以將 Thread 安排在具有?Highest?優(yōu)先級(jí)的線程之后,在具有?Normal?優(yōu)先級(jí)的線程之前。 |
| Highest | 可以將 Thread 安排在具有任何其他優(yōu)先級(jí)的線程之前。 |
?優(yōu)先級(jí)的示例:
using System; using System.Threading;namespace ConsoleApp {class Program{static void Main(string[] args){//新建3個(gè)線程并設(shè)定各自的優(yōu)先級(jí)Thread t1 = new Thread(Run);t1.Priority = ThreadPriority.Lowest;Thread t2 = new Thread(Run);t2.Priority = ThreadPriority.Normal;Thread t3 = new Thread(Run);t3.Priority = ThreadPriority.Highest;//由低到高優(yōu)先級(jí)的順序依次調(diào)用 t1.Start();t2.Start();t3.Start();Console.ReadKey();}public static void Run(){Console.WriteLine("我的優(yōu)先級(jí)是:" + Thread.CurrentThread.Priority);}} } View Code4. 線程的狀態(tài)
通過(guò)ThreadState可以檢測(cè)線程是處于Unstarted、Sleeping、Running 等等狀態(tài),它比 IsAlive 屬性能提供更多的特定信息。
前面說(shuō)過(guò),一個(gè)應(yīng)用程序域中可能包括多個(gè)上下文,而通過(guò)CurrentContext可以獲取線程當(dāng)前的上下文。
CurrentThread是最常用的一個(gè)屬性,它是用于獲取當(dāng)前運(yùn)行的線程。
?
5. System.Threading.Thread的方法
Thread 中包括了多個(gè)方法來(lái)控制線程的創(chuàng)建、掛起、停止、銷毀,以后來(lái)的例子中會(huì)經(jīng)常使用。
| Abort() | 終止本線程。 |
| GetDomain() | 返回當(dāng)前線程正在其中運(yùn)行的當(dāng)前域。 |
| GetDomainId() | 返回當(dāng)前線程正在其中運(yùn)行的當(dāng)前域Id。 |
| Interrupt() | 中斷處于 WaitSleepJoin 線程狀態(tài)的線程。 |
| Join() | 已重載。 阻塞調(diào)用線程,直到某個(gè)線程終止時(shí)為止。 |
| Resume() | 繼續(xù)運(yùn)行已掛起的線程。 |
| Start() | 執(zhí)行本線程。 |
| Suspend() | 掛起當(dāng)前線程,如果當(dāng)前線程已屬于掛起狀態(tài)則此不起作用 |
| Sleep() | 把正在運(yùn)行的線程掛起一段時(shí)間。 |
6. 開(kāi)發(fā)實(shí)例
?前臺(tái)線程與后臺(tái)線程的區(qū)別
我們看到上面有個(gè)屬性叫后臺(tái)線程,非后臺(tái)線程就叫前臺(tái)線程吧,Thread.Start()啟動(dòng)的線程默認(rèn)為前臺(tái)線程,啟動(dòng)程序時(shí)創(chuàng)建的主線程一定是前臺(tái)線程。應(yīng)用程序與必須等到所有的前臺(tái)線程執(zhí)行完畢才會(huì)卸載。而當(dāng)IsBackground設(shè)置為true時(shí),就是后臺(tái)線程了,當(dāng)主線程執(zhí)行完畢后就直接卸載,不再理會(huì)后臺(tái)線程是否執(zhí)行完畢。
前臺(tái)與后臺(tái)線程的設(shè)置必須在線程啟動(dòng)之前進(jìn)行設(shè)置,線程啟動(dòng)之后就不能設(shè)置了。
Thread創(chuàng)建的線程是前臺(tái)線程,線程池中的是后臺(tái)線程。
1、啟動(dòng)線程(.Start) ??1.1、無(wú)參數(shù)的調(diào)用 Thread?t?=?new?Thread(Action); t.Start(); ??1.2、帶參數(shù)的調(diào)用方式一 Thread?t?=?new?Thread(Action<>); t.Start(參數(shù)); ??1.3、帶參數(shù)的調(diào)用方式二 Thread?t?=?new?Thread(()?=>?Action<>(參數(shù))); t.Start(); ??1.4、如果遇到需要返回值,就可以考慮用異步; public?delegate?string?MethodCaller(string?name);//定義個(gè)代理? MethodCaller?mc?=?new?MethodCaller(GetName);? string?name?=?"my?name";//輸入?yún)?shù)? IAsyncResult?result?=?mc.BeginInvoke(name,null,?null);? string?myname?=?mc.EndInvoke(result);//用于接收返回值? public?string?GetName(string?name)????//?函數(shù) { return?name; } using System; using System.Threading;namespace ConsoleApp1 {public delegate string MethodCaller(string name);//定義個(gè)代理 class Program{static void CountNumbers(){int _iterations = 3;for (int i = 1; i <= _iterations; i++){Thread.Sleep(TimeSpan.FromSeconds(0.5));Console.WriteLine("{0} prints {1}", Thread.CurrentThread.Name, i);}}static void Count(object iterations){CountNumbers((int)iterations);}static void CountNumbers(int iterations){for (int i = 1; i <= iterations; i++){Thread.Sleep(TimeSpan.FromSeconds(0.5));Console.WriteLine("{0} prints {1}", Thread.CurrentThread.Name, i);}}static void PrintNumber(int number){Console.WriteLine(number);}static string GetName(string name) // 函數(shù) {int _iterations = 5;for (int i = 1; i <= _iterations; i++){Thread.Sleep(TimeSpan.FromSeconds(0.5));Console.WriteLine("{0} prints {1}", Thread.CurrentThread.Name, i);}return name;}static void Main(string[] args){//無(wú)參數(shù)的調(diào)用var threadOne = new Thread(CountNumbers);threadOne.Name = "ThreadOne";threadOne.Start();threadOne.Join();Console.WriteLine("--------------------------");//帶參數(shù)的調(diào)用方式一var threadTwo = new Thread(Count);threadTwo.Name = "ThreadTwo";threadTwo.Start(3);threadTwo.Join();Console.WriteLine("--------------------------");//帶參數(shù)的調(diào)用方式二var threadThree = new Thread(() => CountNumbers(4));threadThree.Name = "ThreadThree";threadThree.Start();threadThree.Join();Console.WriteLine("--------------------------");//注意在多個(gè)lambda表達(dá)式中使用香港的變量,它們會(huì)共享該變量 這里兩個(gè)線程的參數(shù)都是20int i = 10;var threadFour = new Thread(() => PrintNumber(i));i = 20;var threadFive = new Thread(() => PrintNumber(i));threadFour.Start();threadFive.Start();Console.WriteLine("--------------------------");MethodCaller mc = new MethodCaller(GetName);string name = "my name";//輸入?yún)?shù) IAsyncResult result = mc.BeginInvoke(name, null, null);Console.WriteLine("繼續(xù)主線程的業(yè)務(wù)");string myname = mc.EndInvoke(result);//用于接收返回值 Console.WriteLine(string.Format("result={0}", myname));}} } View Code2、等待線程結(jié)束,會(huì)阻塞當(dāng)前主線程(.Join)
using System; using System.Threading;namespace ConsoleApp1 {class Program{static void Main(string[] args){Console.WriteLine("Starting program...");Thread t = new Thread(PrintNumbersWithDelay);t.Start();t.Join();Console.WriteLine("Thread completed");}static void PrintNumbersWithDelay(){Console.WriteLine("Starting...");for (int i = 1; i <= 5; i++){Thread.Sleep(TimeSpan.FromSeconds(1));Console.WriteLine(i);}}} } View Code3、線程中異常的處理只能在線程調(diào)用中的函數(shù)里面去處理,在外面是接收不到線程中的報(bào)錯(cuò)的
using System; using System.Threading;namespace ConsoleApp1 {class Program{static void Main(string[] args){var t = new Thread(FaultyThread);t.Start();t.Join();//try//{// t = new Thread(BadFaultyThread);// t.Start();//}//catch (Exception ex)//{// //這里捕獲不了線程中的異常// Console.WriteLine("We won't get here!");//} }static void BadFaultyThread(){Console.WriteLine("Starting a Badfaulty thread...");Thread.Sleep(TimeSpan.FromSeconds(2));throw new Exception("Boom!");}static void FaultyThread(){try{Console.WriteLine("Starting a faulty thread...");Thread.Sleep(TimeSpan.FromSeconds(1));throw new Exception("Boom!");}catch (Exception ex){Console.WriteLine("Exception handled: {0}", ex.Message);}}} } View Code4、設(shè)置線程優(yōu)先級(jí)(.Priority)
using System; using System.Diagnostics; using System.Threading;namespace ConsoleApp1 {class Program{static void Main(string[] args){Console.WriteLine("Current thread priority: {0}", Thread.CurrentThread.Priority);Console.WriteLine("Running on all cores available");RunThreads();Thread.Sleep(TimeSpan.FromSeconds(2));Console.WriteLine("Running on a single core");Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);RunThreads();Console.ReadLine();}static void RunThreads(){var sample = new ThreadSample();var threadOne = new Thread(sample.CountNumbers);threadOne.Name = "ThreadOne";var threadTwo = new Thread(sample.CountNumbers);threadTwo.Name = "ThreadTwo";threadOne.Priority = ThreadPriority.Lowest;threadTwo.Priority = ThreadPriority.Highest;threadOne.Start();threadTwo.Start();Thread.Sleep(TimeSpan.FromSeconds(2));sample.Stop();}class ThreadSample{private bool _isStopped = false;public void Stop(){_isStopped = true;}public void CountNumbers(){long counter = 0;while (!_isStopped){counter++;}Console.WriteLine("{0} with {1,11} priority " +"has a count = {2,13}", Thread.CurrentThread.Name,Thread.CurrentThread.Priority,counter.ToString("N0"));}}} } View Code?
?
轉(zhuǎn)載于:https://www.cnblogs.com/scmail81/p/9297068.html
總結(jié)
以上是生活随笔為你收集整理的Thread类(线程)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Eclipse Spring Boot实
- 下一篇: OSChina 周四乱弹 —— 画种稻画