并發(fā)編程的目的是為了讓程序運行的更快滋早,但是并不是啟動更多的線程就能提高程序的運行速度。并發(fā)編程之所以會提高程序的運行速度砌们,在我看來有這幾方面杆麸,第一個是通過并發(fā)編程會充分利用多核 CPU 的優(yōu)勢,即若沒有使用并發(fā)編程可能并沒有完全利用 CPU 的性能浪感;第二個是若程序因為 I/O 或其他任何臨界資源的競爭而使程序不能運行下去時可以通過切換線程去做硬件和軟件資源已經(jīng) ready 的任務(wù)昔头;由于以上兩點并發(fā)編程一般情況下是可以提高程序的運行速度的。但是由于上下文切換問題影兽、死鎖問題揭斧、以及硬件和軟件資源的限制問題等都會對并發(fā)編程帶來很多挑戰(zhàn)。
上下文切換
即使是單核處理器也支持多線程執(zhí)行代碼峻堰, CPU 通過給每個線程分配 CPU 時間片來實現(xiàn)這個機制讹开。時間片是 CPU 分配給各個線程的執(zhí)行時間,由于每個時間片非常短捐名,所以 CPU 通過不停的切換線程執(zhí)行旦万,讓每個線程都以為自己獨占了 CPU。CPU 通過時間片分配算法來循環(huán)執(zhí)行任務(wù)镶蹋,當任務(wù)切換之前會保存當前任務(wù)的狀態(tài)纸型,以便下次時間片到來時恢復(fù)當前任務(wù),任務(wù)從保存再加載的這個過程就是一次上下文切換梅忌。也就是說上下文切換其實是有代價的狰腌,隨著線程的增多上下文切換的代價當然也約大。所以說并不是線程越多程序一定就執(zhí)行越快牧氮。
因此為了減少上下文切換的影響應(yīng)該盡量去減少上下文切換琼腔,減少上下文切換的方法有無鎖并發(fā)編程、 CAS 算法踱葛、使用最少線程和使用協(xié)程
- 無鎖并發(fā)編程丹莲。多線程競爭鎖時會引起上下文切換光坝,所以多線程處理數(shù)據(jù)時可以用一些辦法來避免使用鎖,如將數(shù)據(jù)按 ID Hash 算法取模分段甥材,不同的線程處理不同段的數(shù)據(jù)盯另,其中 ConcurrentHashMap 就是采用了這種方式,后面有機會我會單獨寫一篇文章介紹 ConcurrentHashMap 的原理洲赵。
- CAS 算法鸳惯。Java 的 Atomic 包使用 CAS 算法來更新數(shù)據(jù),而不需要加鎖叠萍,后面我會單獨寫文章介紹 CAS 算法是怎么回事芝发。
- 使用最少線程。避免創(chuàng)建不必要的線程苛谷,這可能是最容易想到的方式了辅鲸。
- 協(xié)程。在單線程里面實現(xiàn)多任務(wù)的調(diào)度腹殿,并在單線程里維持多個任務(wù)的切換独悴。
死鎖
鎖是個非常有用的線程同步工具,運用場景多锣尉、使用簡單绵患、易于理解等。但同時它也會帶來一些問題悟耘,比如死鎖。一旦產(chǎn)生死鎖就會造成系統(tǒng)功能的不可用织狐。
下面我們簡單了解一下死鎖發(fā)生的四個條件暂幼。
- 互斥條件。及某個資源只能同時被一個線程或進程持有移迫,這種資源也叫臨界資源旺嬉。
- 請求保持條件。及一個線程持有了某個臨界資源后還要請求另一個臨界資源厨埋,若另一個資源沒有請求到也不會釋放當前持有的資源邪媳。
- 不可剝奪條件。即一個線程持有了某個臨界資源之后不能強制使其放棄當前持有的資源荡陷。
- 循環(huán)等待雨效。系統(tǒng)中若干進程組成環(huán)路,該環(huán)路中每個進程都在等待相鄰進程正占用的資源废赞。
只有以上四個條件同時滿足時才會發(fā)生死鎖徽龟。下面我們介紹避免死鎖的幾個常用方法。
- 避免一個線程同時獲取多個鎖
- 避免一個線程在鎖內(nèi)同時占用多個資源唉地,盡量保證每個鎖只占用一個資源
- 嘗試使用定時鎖
- 對于數(shù)據(jù)庫鎖据悔,加鎖和解鎖必須在一個數(shù)據(jù)庫連接里
資源限制的條件
資源限制是指在進行并發(fā)編程時传透,程序的執(zhí)行速度受限于計算機硬件或軟件資源。例如极颓,服務(wù)器的帶寬只有 2Mb/s朱盐,某個資源的額下載速度是 1Mb/s ,系統(tǒng)啟動 10 個線程下載資源菠隆,下載速度也最多只有 2Mb/s 兵琳,所以在進行并發(fā)編程時要考慮到資源的限制。硬件資源限制有帶寬的上傳/下載速度浸赫、硬盤讀寫速度和 CPU 的處理速度闰围。軟件資源限制有數(shù)據(jù)庫的連接數(shù)和 socket 連接數(shù)等。
本文簡單介紹了并發(fā)編程中可能遇到的挑戰(zhàn)既峡,并給出了一些解決建議羡榴。并發(fā)程序的問題相比與單線程程序更加難以定位。所以對于 Java 工程師而言在并發(fā)編程時少造輪子盡可能的使用 JDK 并發(fā)包中提供的各種并發(fā)工具去解決并發(fā)問題运敢。