本文系作者 chaoCode原創,轉載請私信並在文章開頭附帶作者和原文地址鏈接。
違者,作者保留追究權利。
前言
並發編程在我們日常開發中是時時刻刻都有在用的,只不過大部分的代碼底層已經幫我們去做了一些並發編程的安全處理,但是還是有很多情況下需要我們自己去控制,所以我們需要去了解學習並發編程,那么我們一步一步深入的開始學習。
如果有小伙伴沒有看過之前的並發編程——基礎概念(一)可以自行觀看。
本篇為概念性的東西,可能比較冗長,請耐心解讀,對於學習並發編程之前我們首先要知道這些基本的概念。
基礎概念
1.澄清並行和並發
我們舉個例子,如果有條高速公路 A 上面並排有 8 條車道,那么最大的並行車 輛就是 8 輛此條高速公路 A 同時並排行走的車輛小於等於 8 輛的時候,車輛就可 以並行運行。CPU 也是這個原理,一個 CPU 相當於一個高速公路 A,核心數或者線 程數就相當於並排可以通行的車道;而多個 CPU 就相當於並排有多條高速公路,而 每個高速公路並排有多個車道。
當談論並發的時候一定要加個單位時間,也就是說單位時間內並發量是多少? 離開了單位時間其實是沒有意義的。
俗話說,一心不能二用,這對計算機也一樣,原則上一個 CPU 只能分配給一個 進程,以便運行這個進程。我們通常使用的計算機中只有一個 CPU,也就是說只有 一顆心,要讓它一心多用同時運行多個進程,就必須使用並發技術。實現並發技術 相當復雜,最容易理解的是“時間片輪轉進程調度算法”。
綜合來說:
並發:指應用能夠交替執行不同的任務,比如單 CPU 核心下執行多線程並非是 同時執行多個任務,如果你開兩個線程執行,就是在你幾乎不可能察覺到的速度不 斷去切換這兩個任務,已達到"同時執行效果",其實並不是的,只是計算機的速度太 快,我們無法察覺到而已。
並行:指應用能夠同時執行不同的任務,例:吃飯的時候可以邊吃飯邊打電話, 這兩件事情可以同時執行
兩者區別:一個是交替執行,一個是同時執行。
2.高並發編程的意義、好處和注意事項
由於多核多線程的 CPU 的誕生,多線程、高並發的編程越來越受重視和關注。 多線程可以給程序帶來如下好處。
充分利用 CPU 的資源
從上面的 CPU 的介紹,可以看的出來,現在市面上沒有 CPU 的內核不使用多線 程並發機制的,特別是服務器還不止一個 CPU,如果還是使用單線程的技術做思路, 明顯就 out 了。因為程序的基本調度單元是線程,並且一個線程也只能在一個 CPU 的一個核的一個線程跑,如果你是個 i3 的 CPU 的話,最差也是雙核心 4 線程的運算 能力:如果是一個線程的程序的話,那是要浪費 3/4 的 CPU 性能:如果設計一個多線 程的程序的話,那它就可以同時在多個 CPU 的多個核的多個線程上跑,可以充分地 利用 CPU,減少 CPU 的空閑時間,發揮它的運算能力,提高並發量。
就像我們平時坐地鐵一樣,很多人坐長線地鐵的時候都在認真看書,而不是為 了坐地鐵而坐地鐵,到家了再去看書,這樣你的時間就相當於有了兩倍。這就是為 什么有些人時間很充裕,而有些人老是說沒時間的一個原因,工作也是這樣,有的 時候可以並發地去做幾件事情,充分利用我們的時間,CPU 也是一樣,也要充分利用。
加快響應用戶的時間
比如我們經常用的迅雷下載,都喜歡多開幾個線程去下載,誰都不願意用一個 線程去下載,為什么呢?答案很簡單,就是多個線程下載快啊。
我們在做程序開發的時候更應該如此,特別是我們做互聯網項目,網頁的響應 時間若提升 1s,如果流量大的話,就能增加不少轉換量。做過高性能 web 前端調優 的都知道,要將靜態資源地址用兩三個子域名去加載,為什么?因為每多一個子域 名,瀏覽器在加載你的頁面的時候就會多開幾個線程去加載你的頁面資源,提升網 站的響應速度。多線程,高並發真的是無處不在。
可以使你的代碼模塊化,異步化,簡單化
例如我們實現電商系統,下訂單和給用戶發送短信、郵件就可以進行拆分, 將給用戶發送短信、郵件這兩個步驟獨立為單獨的模塊,並交給其他線程去執行。 這樣既增加了異步的操作,提升了系統性能,又使程序模塊化,清晰化和簡單化。
多線程應用開發的好處還有很多,大家在日后的代碼編寫過程中可以慢慢體 會它的魅力。
3.多線程程序需要注意事項
線程之間的安全性
從前面的章節中我們都知道,在同一個進程里面的多線程是資源共享的,也就 是都可以訪問同一個內存地址當中的一個變量。例如:若每個線程中對全局變量、 靜態變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的:若有多 個線程同時執行寫操作,一般都需要考慮線程同步,否則就可能影響線程安全。
線程之間的死鎖
為了解決線程之間的安全性引入了 Java 的鎖機制,而一不小心就會產生 Java 線程死鎖的多線程問題,因為不同的線程都在等待那些根本不可能被釋放的鎖,從 而導致所有的工作都無法完成。假設有兩個線程,分別代表兩個飢餓的人,他們必 須共享刀叉並輪流吃飯。他們都需要獲得兩個鎖:共享刀和共享叉的鎖。
假如線程 A 獲得了刀,而線程 B 獲得了叉。線程 A 就會進入阻塞狀態來等待 獲得叉,而線程 B 則阻塞來等待線程 A 所擁有的刀。這只是人為設計的例子,但盡 管在運行時很難探測到,這類情況卻時常發生
線程太多了會將服務器資源耗盡形成死機當機
線程數太多有可能造成系統創建大量線程而導致消耗完系統內存以及 CPU 的“過渡切換”,造成系統的死機,那么我們該如何解決這類問題呢?
某些系統資源是有限的,如文件描述符。多線程程序可能耗盡資源,因為每個 線程都可能希望有一個這樣的資源。如果線程數相當大,或者某個資源的侯選線 程數遠遠超過了可用的資源數則最好使用資源池。一個最好的示例是數據庫連接 池。只要線程需要使用一個數據庫連接,它就從池中取出一個,使用以后再將它返 回池中。資源池也稱為資源庫。
多線程應用開發的注意事項很多,希望大家在日后的工作中可以慢慢體會它 的危險所在。
感謝諸君的觀看,文中如有紕漏,歡迎在評論區來交流。如果這篇文章幫助到了你,歡迎點贊👍和關注。