跳到主要內容

多線程與高併發(一)多線程入門

一、基礎概念


多線程的學習從一些概念開始,進程和線程,併發與并行,同步與異步,高併發。


1.1 進程與線程


幾乎所有的操作系統都支持同時運行期多個任務,所有運行中的任務通常就是一個進程,進程是處於運行過程中的程序,進程是操作系統進行資源分配和調度的一個獨立單位。



進程有三個如下特徵:



  • 獨立性:進程是系統中獨立存在的實體,它可以擁有自己獨立的資源,每一個進程都擁有自己私有的地址空間。在沒有經過進程本身允許的情況下,一個用戶進程不可以直接訪問其他進程的地址空間。


  • 動態性:進程與程序的區別在於,程序只是一個靜態的指令集合,而進程是一個正在系統中活動的指令集合。在進程中加入了時間的概念,進程具有自己的生命周期和各種不同的狀態,這些概念在程序中部是不具備的。


  • 併發性:多個進程可以在單個處理器上併發執行,多個進程之間不會互相影響。



線程是進程的組成部分,一個進程可以擁有多個線程,而線程必須有一個父進程,線程可以有自己的堆棧、自己的程序計數器和自己的局部變量,但不擁有系統資源。比如使用QQ時,我們可以同事傳文件,發送圖片,聊天,這就是多個線程在進行。


線程可以完成一定的任務,線程能夠獨立運行的,它不知道有其他線程的存在,線程的執行是搶佔式的,當前線程隨時可能被掛起。


總之:一個程序運行后至少有一個進程,一個進程里可以有多個線程,但至少要有一個線程。


1.2 併發和并行


併發和并行是比較容易混淆的概念,他們都表示兩個或者多個任務一起執行,但併發側重多個任務交替執行,同一時刻只能有一條指令執行,但多個進程指令被快速輪換執行,使得在宏觀上具有多個進程同時執行的效果。而并行確實真正的同時執行,有多條指令在多個處理器上同時執行,并行的前提條件就是多核CPU。


1.3 同步和異步


同步和異步通常用來形容一次方法調用。同步方法調用一旦開始,調用者必須等到方法調用返回后,才能繼續後續的行為。異步方法調用更像一個消息傳遞,一旦開始,方法調用就會立即返回,調用者可以繼續後續的操作。


1.4 高併發


高併發一般是指在短時間內遇到大量操作請求,非常具有代表性的場景是秒殺活動與搶票,高併發是互聯網分佈式系統架構設計中必須考慮的因素之一,高併發相關常用的一些指標有響應時間(Response Time),吞吐量(Throughput),每秒查詢率QPS(Query Per Second),併發用戶數等。


多線程在這裏只是在同/異步角度上解決高併發問題的其中的一個方法手段,是在同一時刻利用計算機閑置資源的一種方式


1.5 多線程的好處


線程在程序中是獨立的、併發的執行流,擁有獨立的內存單元,多個線程共享父進程里的全部資源,線程共享的環境有進程的代碼段,進程的公有數據等,利用這些共享數據,線程很容易實現相互之間的通信,可以提高程序的運行效率。


多線程的好處主要有:



  • 進程之間不能共享內存,但線程之間共享內存非常容易。


  • 系統創建進程時需要給進程重新分配系統資源,但創建線程代價小得多,所以使用多線程實現多任務併發比多進程效率高


  • Java語言內置了多線程功能支持。



二、使用多線程


上面講了多線程的一些概念,都有些抽象,下面將學習如何使用多線程,創建多線程的方式有三種。


2.1 繼承Thread類創建


繼承Thread創建並啟動多線程有三個步驟:



  1. 定義類並繼承Thread,重寫run()方法,run()方法中為需要多線程執行的任務。


  2. 創建該類的實例,即創建了線程對象。


  3. 調用實例的start()方法啟動線程。



public class FirstThread extends Thread { 

private int i=0;
public void run() {
for (; i < 100; i++) {
//獲取當前線程名稱
System.out.println(this.getName() + " " + i);
}
}

public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
//Thread的靜態方法currentThread,獲取當前線程
System.out.println(Thread.currentThread().getName());
if (i == 20) {
//創建線程並啟動
new FirstThread().start();
new FirstThread().start();
}

}
}
}

運行結果可以看到兩個線程的i並不是連續的,說明他們並不共享數據。


2.2 實現Runnable接口


實現Runnable接口創建並啟動多線程也有以下步驟:



  1. 定義類並繼承Runnable接口,重寫run()方法,run()方法中為需要多線程執行的任務。


  2. 創建該類的實例,並以此實例作為target為參數來創建Thread對象,這個Thread對象才是真正的多線程對象。



public class SecondThread implements Runnable { 
private int i = 0;

@Override
public void run() {
for (; i < 100; i++) {
//此時想要獲取到多線程對象,只能使用Thread.currentThread()方法
System.out.println(Thread.currentThread().getName() + " " + i);
}
}

public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
//Thread的靜態方法currentThread,獲取當前線程
System.out.println(Thread.currentThread().getName());
if (i == 20) {
//創建線程並啟動
SecondThread secondThread=new SecondThread();
new Thread(secondThread,"線程一").start();
new Thread(secondThread,"線程二").start();
}

}
}
}

2.3 使用Callable和Future


Callable是Runnable的增加版,主要是接口中的call()方法可以有返回值,並且可以申明拋出異常,使用Callable創建的步驟如下:



  1. 定義類並繼承Callable接口,重寫call()方法,run()方法中為需要多線程執行的任務。


  2. 創建類實例,使用FutureTask來包裝對象實例,


  3. 使用FutureTask對象作為Thread的target來創建多線程,並啟動線程。


  4. 調用FutureTask對象的get()方法來獲取子線程結束后的返回值。



public class ThirdThread { 

public static void main(String[] args) {
//使用lambda表達式
FutureTask<Integer> task = new FutureTask<>((Callable<Integer>) () -> {
int i = 0;
for (; i < 100; i++) {
System.out.println(Thread.currentThread().getName()
+ "的循環變量i的值:" + i);
}
return i;
});
for (int i = 0; i < 100; i++) {
//Thread的靜態方法currentThread,獲取當前線程
System.out.println(Thread.currentThread().getName());
if (i == 20) {
//創建線程並啟動
new Thread(task, "有返回值的線程").start();
}
}
try {
System.out.println(
"線程的返回值:" + task.get());
}
catch (InterruptedException e) {
e.printStackTrace();
}
catch (ExecutionException e) {
e.printStackTrace();
}
}
}

這裏使用了lambda表達式,不使用表達式的方式也很簡單,可以去源碼中查看。Callable與Runnable方式基本相同,只不過增加了返回值且可允許聲明拋出異常。


使用三種方式都可以創建線程,且方式也相對簡單,大體分為實現接口和實現Thread類兩種,這兩種都各有優缺點。


繼承接口實現:



  • 優點:除了繼承接口之外,還可以繼承其他類。這種方式多個線程共享一個target對象,可以處理用於共同資源的情況。

  • 缺點:編程稍微複雜一些,並且沒有直接獲取當前線程對象的方式,必須使用Thread.currentThread()方式。


基礎Thread類:



  • 優點:編程簡單


  • 缺點:不能繼承其他類



三、多線程的生命周期


線程狀態是線程中非常重要的一個概念,然而我看過很多資料,線程的狀態理解有很多種方式,很多人將其分為五個基本狀態:新建、就緒、運行、阻塞、死亡,但在狀態枚舉中並不是這五個狀態,我不知道是什麼原因(有大神可以解答更好),只能按照枚舉中的狀態根據自己的理解。



  1. 初始(NEW):新創建了一個線程對象,但還沒有調用start()方法,而且就算調用了改方法也不代表狀態立即改變。


  2. 運行(RUNNABLE):在運行的狀態肯定就處於RUNNABLE狀態。


  3. 阻塞(BLOCKED):表示線程阻塞,或者說線程已經被掛起了。


  4. 等待(WAITING):進入該狀態的線程需要等待其他線程做出一些特定動作(通知或中斷)。


  5. 超時等待(TIMED_WAITING):該狀態不同於WAITING,它可以在指定的時間后自行返回。


  6. 終止(TERMINATED):表示該線程已經執行完畢。



狀態流程圖如下:



理解:初始狀態很好理解,這個時候其實還不能被稱為一個線程,因為他還沒被啟動,當調用start()方法后,線程正式啟動,但是也不代表立即就改變了狀態。


運行狀態中其實包含兩種狀態,運行中(RUNING)就緒(READY)


就緒狀態表示你有資格運行,只要CPU還未調度到你,就處於就緒狀態,有幾個狀態會是線程狀態編程就緒狀態



  • 調用線程的start()方法。


  • 當前線程sleep()方法結束,其他線程join()結束,等待用戶輸入完畢,某個線程拿到對象鎖。


  • 當前線程時間片用完了,調用當前線程的yield()方法。


  • 鎖池裡的線程拿到對象鎖后。



運行中(RUNING)狀態比較好理解,線程調度程序選擇了當前線程作。


阻塞狀態是線程阻塞在進入synchronized關鍵字修飾的方法或代碼塊(獲取鎖)時的狀態。


等待狀態是指線程沒有被CPU分配執行時間,需要等待,這種等待是需要被显示的喚醒,否則會無限等待下去。


超時等待狀態是這現在沒有被CPU分配執行時間,需要等待,不過這種等待不需要被显示的喚醒,會設置一定的時間后zi懂喚醒。


死亡狀態也很好理解,說明線程方法被執行完成,或者出錯了,線程一旦進入這個狀態就代表徹底的結束


 

【精選推薦文章】



智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選



想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計



帶您來看台北網站建置台北網頁設計,各種案例分享



廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益



Orignal From: 多線程與高併發(一)多線程入門

留言

這個網誌中的熱門文章

強強聯手!攜手打造雲林縣Web3.0 領地方品牌進軍元宇宙

中華電信攜手國內最大Potato Media Web3.0社群共享平台,及品牌醫生果俐文創三方結合,透過經濟部「CBMP智慧雲遊跨域串連計畫」,協助品牌數位轉型,帶動品牌體驗情境、新商業模組升級與行動支付應用,第一站選在雲林縣當地原生消費品牌,打造社群消費循環,探索近期最夯的元宇宙新玩法。 Potato Media執行長顏宏霖表示,在CBMP計畫協助下,加上站內Web3.0資源,將快速協助雲林縣當地品牌升級轉型,幫助店家創造品牌價值,包含黑矸仔醬油、四代目麥芽酥、玉津烘焙坊、禪屋米胖工坊、YuDS沐耳飲、莫蒂精品巧克力、維野納複合式餐飲、頂雲咖啡、媽祖埔豆腐張、玉山碾米廠等,另外嘉義市麥麵、名香茗茶也等不及跨縣市加入,結合Potato Media站內活動,打造雲林專屬限定NFT道具與頭框,發行雲林扭蛋,體驗全新元宇宙新世界。 左起雲林縣計畫處處長李明岳、果俐文創執行長-陳郁涵、雲林縣議員周秀月、中華電信雲林營運處總經理張肇家、Potato Media執行長顏宏霖、LINE禮物代表睿鼎數位、12CMTaiwan行銷總監楊涵柔。(圖/由Potato Media提供) 此次Potato Media平台合作內容是店家會員註冊活動:首次註冊可得100積分 + 一顆扭蛋,店家推薦文章介紹,可領取店家消費優惠券,站內扭蛋禮物抽獎活動,獎項豐富:雲林限定禮品、雲林意象限定NFT道具與頭框,雲林幣扭一下APP政令大聲公獎勵活動,另外各種雲林美食伴手禮、住宿旅遊的店家,都可以使用行動支付或上LINE禮物平台實際體驗消費。 推薦評價好的 iphone維修 中心 擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢 產品缺大量曝光嗎?你需要的是一流 包裝設計 窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。 雲林縣副縣長謝淑亞強調,此次計畫和Potato Media 合作,Potato Media 是一個在 2021 年 4 月正式發布的「區塊鏈 Web3.0 共享社群平台」,創作者和使用者都可以透過互動的機制,例如對文章點讚、留言與轉發分享,來獲取相對應比例的加密貨幣CFO(Potato Media 平台上的原生加密貨幣),跟Facebook、Instagram、YouTu...

要上網站行銷農產品,得經過市政府抽驗農藥殘留,檢驗合格才能上網行銷

台北網站設計      網頁設計公司     網站設計公司 食安五環為「源頭控管」、「重建生產管理履歷」、「提高查驗能力」、「加重生產者、廠商的責任」及「鼓勵、創造監督平臺」五大要環,除推動政府與市民消費者共同監督食品安全,更要從農場到餐桌,鏈結農村產業線,以網路社群為媒介,建立嘉義市農村網頁平台。活動現場介紹「農抵嘉」產銷網頁平台的內容,包含在地人文地產景,將景觀、產業、生態及文化等資訊整合、展現,更推廣在地農村農友優質、安全的農產品。要上「農抵嘉」網站行銷農產品,得經過市政府抽驗農藥殘留,檢驗合格才能上網行銷自己的農產品,嘉義市農友可以多利用,也提供店家採購管道。 「尚安心,農抵嘉」,透過「農抵嘉」產銷網頁平台,鏈結農村產業線並促進地產地消,從源頭管理食安,讓政府管理、民間參與,透過食安小教育,讓小朋友接觸農作物,與生產者互動,產生共鳴,一同攜手維護嘉義市的食安。記者會中也展示紅瓦厝社區所做的紅瓦窯烤,並有其他下埤花生等農產品,透過農場職人使「農特產品不只是農產品」,民眾可登入「農抵嘉」網頁http://chiayirural.com/index.asp瞭解更進一步的訊息。 網動廣告 參考資料:蕃新聞https://n.yam.com/Article/20171226529712 Orignal From: 要上網站行銷農產品,得經過市政府抽驗農藥殘留,檢驗合格才能上網行銷

IEA:疫情衝擊能源需求 但再生能源呈創紀錄成長_台中搬家公司

※ 台中搬家公司 教你幾個打包小技巧,輕鬆整理裝箱! 還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」 摘錄自2020年11月10日中央社報導 國際能源總署(IEA)報告今天(10日)指出,武漢肺炎(COVID-19)疫情可能衝擊能源需求,但電力部門再生能源繼續以創紀錄速度成長。 IEA執行董事比羅爾(Fatih Birol)表示:「在2025年,再生能源將成為全球最大發電來源,預計將提供1/3的全球電力,終結煤炭50年來作為最大電力供應來源的地位。」 ※推薦 台中搬家公司 優質服務,可到府估價 台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家 IEA關於再生能源的年度報告估計,儘管受到疫情干擾,今年的再生能源新發電容量可望創紀錄,達將近200GW(GW為十億瓦)。 能源轉型 國際新聞 再生能源 疫情看氣候與能源 本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理 ※ 台中搬家公司 教你幾個打包小技巧,輕鬆整理裝箱! 還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」 Orignal From: IEA:疫情衝擊能源需求 但再生能源呈創紀錄成長_台中搬家公司