Java 并發(fā)編程之并發(fā)編程的挑戰(zhàn)

并發(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ù),當(dāng)任務(wù)切換之前會保存當(dāng)前任務(wù)的狀態(tài),以便下次時間片到來時恢復(fù)當(dāng)前任務(wù),任務(wù)從保存再加載的這個過程就是一次上下文切換。也就是說上下文切換其實是有代價的,隨著線程的增多上下文切換的代價當(dāng)然也約大。所以說并不是線程越多程序一定就執(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ā)生的四個條件。

  • 互斥條件。及某個資源只能同時被一個線程或進(jìn)程持有,這種資源也叫臨界資源。
  • 請求保持條件。及一個線程持有了某個臨界資源后還要請求另一個臨界資源,若另一個資源沒有請求到也不會釋放當(dāng)前持有的資源。
  • 不可剝奪條件。即一個線程持有了某個臨界資源之后不能強制使其放棄當(dāng)前持有的資源。
  • 循環(huán)等待。系統(tǒng)中若干進(jìn)程組成環(huán)路,該環(huán)路中每個進(jìn)程都在等待相鄰進(jìn)程正占用的資源。

只有以上四個條件同時滿足時才會發(fā)生死鎖。下面我們介紹避免死鎖的幾個常用方法。

  • 避免一個線程同時獲取多個鎖
  • 避免一個線程在鎖內(nèi)同時占用多個資源,盡量保證每個鎖只占用一個資源
  • 嘗試使用定時鎖
  • 對于數(shù)據(jù)庫鎖,加鎖和解鎖必須在一個數(shù)據(jù)庫連接里

資源限制的條件

資源限制是指在進(jìn)行并發(fā)編程時,程序的執(zhí)行速度受限于計算機硬件或軟件資源。例如,服務(wù)器的帶寬只有 2Mb/s,某個資源的額下載速度是 1Mb/s ,系統(tǒng)啟動 10 個線程下載資源,下載速度也最多只有 2Mb/s ,所以在進(jìn)行并發(fā)編程時要考慮到資源的限制。硬件資源限制有帶寬的上傳/下載速度、硬盤讀寫速度和 CPU 的處理速度。軟件資源限制有數(shù)據(jù)庫的連接數(shù)和 socket 連接數(shù)等。

本文簡單介紹了并發(fā)編程中可能遇到的挑戰(zhàn),并給出了一些解決建議。并發(fā)程序的問題相比與單線程程序更加難以定位。所以對于 Java 工程師而言在并發(fā)編程時少造輪子盡可能的使用 JDK 并發(fā)包中提供的各種并發(fā)工具去解決并發(fā)問題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容