網站首頁 編程語言 正文
線程
線程:對于所有需要等待的操作,例如移動文件,數據庫和網絡訪問都需要一定的時間,此時就可以啟動一個新的線程,同時完成其他任務。一個進程的多個線程可以同時運行在不同的CPU上或多核CPU的不同內核上。
一個應用程序啟動時,會啟動一個進程(應用程序的載體),然后進程會啟動多個線程。
一,使用Thread類啟動線程和數據傳輸
使用Thread類可以創建和控制線程,Thread構造函數是一個無參無返回值的委托類型。
1??對Thread傳入一個無參無返回類型的方法-ThreadStart。
public delegate void ThreadStart();
實例:
static void test() { Console.WriteLine("test is start"); Console.WriteLine("test is running"); Thread.Sleep(3000); Console.WriteLine("test is completed"); } static void Main(string[] args) { Thread th = new Thread(test); th.Start(); Console.WriteLine("main is completed"); }
2??對Thread傳入一個匿名方法(或lambda表達式)。用于傳入的方法代碼簡單的情況
static void Main(string[] args) { //lambad表達式 Thread th = new Thread(()=> { Console.WriteLine("子線程1-ID:" + Thread.CurrentThread.ManagedThreadId); }); th.Start(); //匿名方法 Thread th2 = new Thread(delegate () { Console.WriteLine("子線程2-ID:" + Thread.CurrentThread.ManagedThreadId); }); th2.Start(); Console.WriteLine("main is completed"); }
3??對Thread傳入一個無返回值有參方法-ParameterizedThreadStart,該參數只能是object類型且只能有一個參數。
public delegate void ParameterizedThreadStart(object? obj);
實例:
static void download(object o) { string str = o as string; Console.WriteLine("地址:" + str); } static void Main(string[] args) { Thread th = new Thread(download); th.Start("http://baidu.com"); Console.WriteLine("main is completed"); }
注意:使用as進行強制類型轉換 成功會正確輸出,失敗會輸出null。
以上數據傳輸的方法都是基于靜態變量進行傳輸的,但是定義過多靜態變量會導致多個線程訪問同一個靜態變量,造成資源沖突。
靜態變量雖然方便訪問,但是靜態的一般都是公共的,容易混亂。
4??對Thread傳入一個無返回值多個參數的方法(定義一個結構體),但是不能用as強制轉換。
public struct data { public string message; public int age; } static void download(object o) { data str = (data)o;//強制類型轉換 Console.WriteLine("信息:" + str.message); Console.WriteLine("年紀:" + str.age); } static void Main(string[] args) { data da = new data(); da.message = "sss"; da.age = 3; Thread th = new Thread(download); th.Start(da); Console.WriteLine("main is completed"); }
由于結構體是值類型,不能為null,因此不能用as進行強制類型轉換。
5??通過自定義類傳遞數據(即將通過線程調用一個類的成員方法)
先創建一個download類:
class downLoad { public string URL { get; private set; } public string Message { get; private set; } //構造函數 public downLoad(string uRL, string message) { URL = uRL; Message = message; } //下載方法 public void load() { Console.WriteLine("從" + URL + "獲取信息:" + Message); } }
在主程序中將該類的成員方法傳入Thread中:
static void Main(string[] args) { var download = new downLoad("www.baidu.com", "mp4"); Thread th = new Thread(download.load); th.Start(); Console.WriteLine("main is completed"); Console.ReadKey(); }
??知識點拓展1-前臺線程與后臺線程:
應用程序的進程需要等待所有前臺線程完成其任務后才會結束。而后臺線程在應用程序關閉后會自動關閉,即使后臺線程還沒有執行完畢。在默認情況下,用Thread類創建的線程是前臺線程,線程池中的線程是后臺線程。在Thread類創建線程的時候,可以設置IsBackground屬性,表示它是否是一個后臺線程。
??知識點拓展2-線程的優先級
線程有操作系統調度,一個CPU同一時間只能做一件事(運行一個線程中的計算任務),當有很多線程需要CPU執行時,線程調度器會根據線程的優先級去判斷先去執行哪個線程,如果優先級相同,就使用一個循環調度規則,逐個執行每個線程。
在Thread類中,可以設置Priority屬性,以影響線程的基本優先級,Priority屬性一個ThreadPriority枚舉定義的一個值,定義級別有Highest,AboveNormal,Normal,BelowNormal,和Lowest。
因此對于重要的線程任務,可以將線程優先級設置高一點,使其可以盡快執行完畢。
如果需要等待線程執行結果在執行后面的代碼,可以調用Thread對象的join方法,即將該線程加入進來,并停止當前線程,直至加入的線程執行完畢。
二,線程池ThreadPool類
由于線程的創建需要時間,如果有不同的小任務要完成,就可以事先創建多個線程。系統有一個ThreadPool類來管理線程,這個類會在需要線程的時候增加線程數,不需要時候減少。池中最大線程數是可配置的。在雙核CPU中,默認設置為1023個工作線程和1000個IO線程,如果需要更多線程(超過了線程池的最大數量),最新的任務就需要排隊等待。
使用線程池,即調用ThreadPool.QueueUserWorkItem方法,該方法需要傳入一個WaitCallBack類型的委托(即傳入帶一個object參數的方法)。然后ThreadPool會在池中找一個空閑的線程去執行傳入的方法。
static void Main(string[] args) { for (int i = 0; i < 10; i++) { ThreadPool.QueueUserWorkItem(work); } Thread.Sleep(10000); } static void work(object state) { Console.WriteLine("線程id" + Thread.CurrentThread.ManagedThreadId); }
需要注意的是:
線程池中所有線程都是后臺線程,如果進程中所有的前臺線程都結束了,所有的后臺線程也會跟著結束。不能把入池的后臺線程改為前臺線程。不能給入池的線程設置優先級或名稱。入池的線程只能是用于時間較短的任務。如果線程要一直運行,就應用Thread類創建一個線程。
任務
任務表示應完成某個單元的工作,這個工作可以在單獨的線程中運行,也可以同步方式啟動一個任務。任務在后臺使用ThreadPool進行管理的,也就是說任務啟動的也是后臺線程。
一,創建并啟動任務
啟動任務的兩種方式:
static void Main(string[] args) { //第一種:使用TaskFactory TaskFactory tf = new TaskFactory(); tf.StartNew(work); //第二種:使用Task Task t = new Task(work); t.Start(); Console.WriteLine("main is completed"); } static void work() { Console.WriteLine("線程id" + Thread.CurrentThread.ManagedThreadId); }
需要注意的是:使用TaskFactory創建任務,傳入的方法為無參的。
二,連續任務
如果一個任務t1的執行是依賴于另一個任務t2,那么就需要在t2執行完畢后才開始執行t1。(例如:迅雷下載完成后彈出界面提示)這時候我們可以使用連續任務ContinueWith。
static void Main(string[] args) { Task t1 = new Task(download); Task t2 = t1.ContinueWith(show); t1.Start(); Thread.Sleep(2000); } static void download() { Console.WriteLine("正在下載中。。。。"); Thread.Sleep(1000); } static void show(Task t) { Console.WriteLine("下載完成!"); }
需要注意的是:傳入t2的方法的參數需為Task類型。
三,資源沖突問題
在多線程中如果多個線程同時訪問同一資源,就會產生資源沖突的問題。這時候需要用lock對程序進行加鎖。
??什么是資源沖突?
class state { public int num = 5; public void checknum() { if (num==5) { num++; Console.WriteLine("num的值:" + num + "當前線程id:" + Thread.CurrentThread.ManagedThreadId); } num =5; } }
static void Main(string[] args) { state st = new state(); for (int i = 0; i < 10; i++) { Thread th = new Thread(st.checknum); th.Start(); } }
在主程序使用多線程調用state類的check方法,可以看到num=5和num=6造成資源沖突了。
??對多個線程訪問的對象進行加鎖
object _lock = new object(); public int num = 5; public void checknum() { lock(_lock) { if (num==5) { num++; Console.WriteLine("num的值:" + num + "當前線程id:" + Thread.CurrentThread.ManagedThreadId); } num =5; } }
?總結
原文鏈接:https://www.cnblogs.com/xyf327/p/16010782.html
相關推薦
- 2023-03-18 pandas檢查和填充缺失值的N種方法總結_python
- 2022-12-27 pytorch?K折交叉驗證過程說明及實現方式_python
- 2022-07-18 Linux tar命令;sftp;創建變量;find命令;history命令;引號的使用舉例;
- 2022-11-10 Linux實現壓縮文件的生成與查看的常用命令總結_linux shell
- 2022-05-17 【go】解決“dial tcp 142.251.42.241:443: connect: conne
- 2023-07-10 Django進行docker服務器部署
- 2022-12-05 Python中的內置函數isdigit()_python
- 2022-03-21 導出與導入Docker的容器實現示例_docker
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支