手機營銷網(wǎng)站模板怎樣建立一個網(wǎng)絡(luò)銷售平臺
文章目錄
- 1.1上下文切換
- (1)上下文切換的概念
- (2)多線程一定比單線程快嗎?
- (3)測量上下文切換
- 如何減少上下文切換
- 1.2 死鎖
- (1)死鎖的定義
- (2)死鎖產(chǎn)生的四個必要條件
- (2)死鎖的解決方法
- 1.3 資源限制的挑戰(zhàn)
- (1)資源限制的定義
- (2)資源限制引發(fā)的問題
- (3)解決資源限制的方法
- (4)在資源限制下的并發(fā)編程
并發(fā)編程旨在通過多線程執(zhí)行任務(wù)來提高程序的運行效率,但實現(xiàn)并發(fā)并不總是能帶來預(yù)期的速度提升。多線程的執(zhí)行效率受到多個因素的影響,主要包括上下文切換、死鎖和硬件/軟件資源限制等問題。本章介紹了這些挑戰(zhàn)以及相應(yīng)的解決方案。
1.1上下文切換
(1)上下文切換的概念
-
定義:上下文切換是指CPU在不同線程之間切換執(zhí)行時,需要保存當前線程的狀態(tài),并加載下一個線程的狀態(tài)。
-
原理:單核處理器通過時間片(幾十毫秒)分配CPU時間,使得多個線程看起來像是并行執(zhí)行的。上下文切換會帶來性能開銷,因為每次切換都需要保存和恢復(fù)線程的上下文。
例子:通過讀兩本書來類比,類似于在讀一本英文技術(shù)書時,每次查字典時都需要記住當前進度并切換任務(wù),這種切換會影響效率。
(2)多線程一定比單線程快嗎?
- 測試代碼:比較并發(fā)和串行執(zhí)行相同的累加任務(wù)的時間。
public class ConcurrencyTest {private static final long count = 10000l;public static void main(String[] args) throws InterruptedException {concurrency();serial();}private static void concurrency() throws InterruptedException {long start = System.currentTimeMillis();Thread thread = new Thread(new Runnable() {@Overridepublic void run() {int a = 0;for (long i = 0; i < count; i++) {a += 5;}}});thread.start();int b = 0;for (long i = 0; i < count; i++) {b--;}long time = System.currentTimeMillis() - start;thread.join();System.out.println("concurrency :" + time+"ms,b="+b);}private static void serial() {long start = System.currentTimeMillis();int a = 0;for (long i = 0; i < count; i++) {a += 5;}int b = 0;for (long i = 0; i < count; i++) {b--;}long time = System.currentTimeMillis() - start;System.out.println("serial:" + time+"ms,b="+b+",a="+a);}
}
測試結(jié)果:
- 結(jié)論:并發(fā)執(zhí)行不一定比串行快,特別是任務(wù)次數(shù)較少時。原因是線程的創(chuàng)建和上下文切換的開銷。測試表明,當任務(wù)量不夠大時,線程的管理和切換反而可能讓程序變慢。
(3)測量上下文切換
-
使用工具:
- Lmbench3:測量上下文切換的時長。
- vmstat:測量上下文切換的次數(shù)。
示例命令:
vmstat 1
輸出中的 CS(Context Switches)表示每秒的上下文切換次數(shù)。
如何減少上下文切換
解決方案:
- 無鎖并發(fā)編程:避免鎖競爭,減少上下文切換。通過設(shè)計合適的數(shù)據(jù)分割和線程劃分,減少鎖的使用。
- CAS(Compare And Swap)算法:Java的
Atomic
包通過CAS實現(xiàn)無鎖的并發(fā)操作。 - 使用最少的線程:避免創(chuàng)建不必要的線程,避免過多線程造成的上下文切換。
- 協(xié)程:通過協(xié)程在單線程中實現(xiàn)任務(wù)切換,從而避免多線程的上下文切換開銷。
1.2 死鎖
(1)死鎖的定義
-
死鎖是指兩個或多個線程互相等待對方釋放鎖,從而導(dǎo)致無法繼續(xù)執(zhí)行。
示例代碼:
public class DeadLockDemo {private static String A = "A";private static String B = "B";public static void main(String[] args) {new DeadLockDemo().deadLock();}private void deadLock() {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (A) {try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }synchronized (B) {System.out.println("1");}}}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (B) {synchronized (A) {System.out.println("2");}}}});t1.start();t2.start();} }
代碼中的
Thread-1
和Thread-2
相互等待對方的鎖,造成死鎖。
(2)死鎖產(chǎn)生的四個必要條件
- 互斥(Mutual Exclusion):資源只能被一個線程或進程占有,且其他線程或進程必須等待。例如,一個線程占用某個鎖,其他線程就無法訪問該資源,直到鎖被釋放。
- 占有且等待(Hold and Wait):線程或進程已經(jīng)持有某些資源,同時又請求其他資源,而這些資源當前被其他線程或進程占用。
- 不可剝奪(No Preemption):已經(jīng)分配給線程或進程的資源,在沒有釋放之前不能被其他線程或進程強行搶占。只有線程或進程自己釋放資源,其他線程才能獲得資源。
- 循環(huán)等待(Circular Wait):存在一個資源的等待鏈,其中每個線程或進程都在等待下一個線程或進程所持有的資源,形成一個閉環(huán)。
(2)死鎖的解決方法
- 破壞循環(huán)等待條件
資源的順序分配
:最常見的解決方法是對資源加鎖時,按照一定的順序來申請資源,避免出現(xiàn)循環(huán)等待。例如,為每個資源分配一個唯一的編號,然后線程總是按照資源編號的順序來申請資源。如果線程按順序申請資源,就不會出現(xiàn)循環(huán)等待的情況。 - 破壞占有且等待條件
一次性申請所有資源
:要求線程在執(zhí)行時一次性申請它需要的所有資源,而不是在持有一部分資源時,再去申請其他資源。這樣可以避免線程在持有部分資源的同時等待其他資源,從而避免占有且等待條件。 - 破壞非搶占條件
搶占資源
:當線程申請資源失敗時,系統(tǒng)可以強制剝奪線程持有的資源并將其返回給資源池。被搶占的線程可以在稍后重新嘗試獲取資源。這種方法通過破壞非搶占條件來避免死鎖。 - 破壞互斥條件
使用共享資源
:通過將資源的互斥性降低,即允許多個線程共享資源,來避免死鎖。比如,對于讀寫操作,可以使用 讀寫鎖,使得多個線程可以同時讀取共享資源,但寫操作仍然是獨占的。此方法只適用于資源可以共享的場景,通常是讀取操作較多的情況。 - 銀行家算法
詳情可見 銀行家算法:死鎖避免的經(jīng)典策略
1.3 資源限制的挑戰(zhàn)
(1)資源限制的定義
資源限制是指硬件或軟件資源(如帶寬、CPU、內(nèi)存、數(shù)據(jù)庫連接數(shù)等)的限制,可能會影響程序并發(fā)執(zhí)行的效果。資源限制可能導(dǎo)致并發(fā)執(zhí)行時,程序反而執(zhí)行更慢。
(2)資源限制引發(fā)的問題
- 如果并發(fā)的代碼段依賴于硬件或軟件資源,過多的線程會使得程序反而變慢。例如:
- 帶寬限制:如果有多個線程同時下載文件,而帶寬有限,線程多了反而會因為等待帶寬而導(dǎo)致執(zhí)行時間變長。
- 數(shù)據(jù)庫連接數(shù)限制:如果數(shù)據(jù)庫的連接數(shù)有限,而線程數(shù)過多,則會因為線程被阻塞等待連接,導(dǎo)致程序性能下降。
(3)解決資源限制的方法
- 硬件資源限制:使用集群并行執(zhí)行任務(wù),分布式計算框架如Hadoop、ODPS等可以有效利用多臺機器的資源。
- 軟件資源限制:使用資源池技術(shù),復(fù)用數(shù)據(jù)庫連接池或Socket連接池。
(4)在資源限制下的并發(fā)編程
根據(jù)資源限制調(diào)整并發(fā)度。例如,在文件下載程序中,既依賴帶寬又依賴硬盤讀寫速度。如果帶寬有限,增加過多線程不會加速下載,反而可能導(dǎo)致過度的上下文切換,增加執(zhí)行時間。