Java併發系列之併發編程的挑戰

前言

文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/bin392328206/six-finger
種一棵樹最好的時間是十年前,其次是現在
我知道很多人不玩qq了,但是懷舊一下,歡迎加入六脈神劍Java菜鳥學習羣,羣聊號碼:549684836 鼓勵大家在技術的路上寫博客

絮叨

從今天開始,我們進入一個新的領域學習,這個領域的學習,我打算跟着Java併發編程的藝術走,整本書是十一章,意味着我會寫十篇左右博客在Java併發系列中,我希望通過我對這本書的總結,能讓大家在面試和實際工作中運用上Java的併發知識

Java併發編程的藝術

這本書還算可以吧,畢竟是阿里專家寫的,然後我其實很早就買了,但是沒怎麼看,剛好因爲大家喜歡我的文章,那我就很有動力去學習,然後把學到的知識分享給大家,

總共的章節有

  • 併發編程的挑戰

  • Java併發機制的底層實現

  • Java內存模型

  • Java併發編程基礎

  • Java中的鎖

  • Java併發容器和框架(前面講Java容器提到過)

  • Java中的13個原子類

  • Java中併發的工具類

  • Java中的線程池

  • Executor框架

  • 實戰(這個是案例)

JUC

這個肯定要知道是啥的,它是Java JDK中的一個安全包,別等面試官問你有沒有接觸過JUC,你連聽都沒有聽到過,就尷尬了。

在 Java 5.0 提供了java.util.concurrent(簡稱JUC)包,在此包中增加了在併發編程中很常用的工具類, 用於定義類似於線程的自定義子系統,包括線程池,異步 IO 和輕量級任務框架;還提供了設計用於多線程上下文中 的 Collection 實現等;

其實我們要講的併發系列,也就是講上圖的內容來的。

併發編程的目的與挑戰

併發編程的目的是爲了讓程序運行得更快。啓動更多的線程並不一定就能讓程序最大限度地併發執行。
希望通過多線程執行任務讓程序運行得更快,會面臨非常多的挑戰。比如

  • 上下文切換 的問題

  • 死鎖 的問題

  • 硬件和軟件的資源限制問題

上下文切換

單核處理器也支持多線程執行代碼,CPU通過給每個線程分配CPU時間片來實現這個機制。時間片是CPU分配給各個線程的時間,因爲時間片非常短,所以CPU通過不停地切換線程執行,讓我們感覺多個線程是同時執行的,時間片一般是幾十毫秒(ms)。

CPU通過時間片分配算法來循環執行任務,當前任務執行一個時間片後會切換到下一個任務。但是,在切換前會保存上一個任務的狀態,以便下次切換回這個任務時,可以再加載這個任務的狀態。所以任務從保存到再加載的過程就是一次上下文切換。

這個的意思就是告訴我們,並不是說線程越多越好,因爲每個線程的使用cpu的時間是根據算法算出來的,也差不多算平均吧,如果你的線程太多,但是有很多線程是空閒狀態,那你們你上下文切換的時間就是浪費的,這樣還不如單線程執行呢,還有就是執行的次數,如果執行的次數少,那麼串行也會比較快,有實驗證明在10W循環執行中,2者的速度差不多

我們如何去減少上下文的切換

減少上下文切換的方法有 無鎖併發編程、CAS算法、使用最少線程 和 使用協程。

  • 無鎖併發編程。多線程競爭鎖時,會引起上下文切換,所以多線程處理數據時,可以用一些辦法來避免使用鎖,如將數據的ID按照Hash算法取模分段,不同的線程處理不同段的數據。

  • CAS算法。Java的Atomic包使用CAS算法來更新數據,而不需要加鎖。

  • 使用最少線程。避免創建不需要的線程,比如任務很少,但是創建了很多線程來處理,這樣會造成大量線程都處於等待狀態。

  • 協程:在單線程裏實現多任務的調度,並在單線程裏維持多個任務間的切換。

死鎖

所謂死鎖,是指多個進程在運行過程中因爭奪資源而造成的一種僵局,當進程處於這種僵持狀態時,若無外力作用,它們都將無法再向前推進。因此我們舉個例子來描述,如果此時有一個線程A,按照先鎖a再獲得鎖b的的順序獲得鎖,而在此同時又有另外一個線程B,按照先鎖b再鎖a的順序獲得鎖。如下圖所示:

死鎖產生的4個必要條件?

  • 互斥條件:進程要求對所分配的資源進行排它性控制,即在一段時間內某資源僅爲一進程所佔用。

  • 請求和保持條件:當進程因請求資源而阻塞時,對已獲得的資源保持不放。

  • 不剝奪條件:進程已獲得的資源在未使用完之前,不能剝奪,只能在使用完時由自己釋放。

  • 環路等待條件:在發生死鎖時,必然存在一個進程--資源的環形鏈。

預防死鎖:

  • 避免一個線程同時獲取多個鎖。

  • 避免一個線程在鎖內同時佔用多個資源,儘量保證每個鎖只佔用一個資源。

  • 嘗試使用定時鎖,使用lock.tryLock(timeout)來替代使用內部鎖機制。(鎖超時)

  • 對於數據庫鎖,加鎖和解鎖必須在一個數據庫連接裏,否則會出現解鎖失敗的情況。

資源限制的挑戰

  • 硬件資源限制有帶寬的上傳/下載速度、硬盤讀寫速度和CPU的處理速度。

  • 軟件資源限制有數據庫的連接數和socket連接數等。

如何解決資源限制的問題

  • 對於硬件資源限制,可以考慮使用集羣並行執行程序。比如使用ODPS、Hadoop或者自己搭建服務器集羣,要麼用阿里雲的服務。

  • 對於軟件資源限制,可以考慮使用資源池將資源複用。比如使用連接池將數據庫和Socket連接複用,或者在調用對方webservice接口獲取數據時,只建立一個連接。

本章總結

作者的建議是使用JDK併發包下的容器和工具類來解決併發問題,因爲這些是已經經過了大量的測試,可以解決前面提到的幾個挑戰

結尾

第一章 介紹了併發的目的,和挑戰,從全局大觀上知道我們要學習的一個方向,繼續加油吧。

因爲博主也是一個開發萌新 我也是一邊學一邊寫 我有個目標就是一週 二到三篇 希望能堅持個一年吧 希望各位大佬多提意見,讓我多學習,一起進步。

日常求贊

好了各位,以上就是這篇文章的全部內容了,能看到這裏的人呀,都是神人

創作不易,各位的支持和認可,就是我創作的最大動力,我們下篇文章見

六脈神劍 | 文 【原創】如果本篇博客有任何錯誤,請批評指教,不勝感激 !

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章