亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

JAVA多線程的使用場景與注意事項總結

2024-07-14 08:43:42
字體:
來源:轉載
供稿:網友

前言

我曾經對自己的小弟說,如果你實在搞不清楚什么時候用HashMap,什么時候用ConcurrentHashMap,那么就用后者,你的代碼bug會很少。

他問我:ConcurrentHashMap是什么? -.-

編程不是炫技。大多數情況下,怎么把代碼寫簡單,才是能力。

多線程生來就是復雜的,也是容易出錯的。一些難以理解的概念,要規避。本文不講基礎知識,因為你手里就有jdk的源碼。

線程

Thread

第一類就是Thread類。大家都知道有兩種實現方式。第一可以繼承Thread覆蓋它的run方法;第二種是實現Runnable接口,實現它的run方法;而第三種創建線程的方法,就是通過線程池。

我們的具體代碼實現,就放在run方法中。

我們關注兩種情況。一個是線程退出條件,一個是異常處理情況。

線程退出

有的run方法執行完成后,線程就會退出。但有的run方法是永遠不會結束的。結束一個線程肯定不是通過Thread.stop()方法,這個方法已經在java1.2版本就廢棄了。所以我們大體有兩種方式控制線程。

定義退出標志放在while中

代碼一般長這樣。

private volatile boolean flag= true;public void run() { while (flag) { }}

標志一般使用volatile進行修飾,使其讀可見,然后通過設置這個值來控制線程的運行,這已經成了約定俗成的套路。

使用interrupt方法終止線程

類似這種。

while(!isInterrupted()){……}

對于InterruptedException,比如Thread.sleep所拋出的,我們一般是補獲它,然后靜悄悄的忽略。中斷允許一個可取消任務來清理正在進行的工作,然后通知其他任務它要被取消,最后才終止,在這種情況下,此類異常需要被仔細處理。

interrupt方法不一定會真正”中斷”線程,它只是一種協作機制。interrupt方法通常不能中斷一些處于阻塞狀態的I/O操作。比如寫文件,或者socket傳輸等。這種情況,需要同時調用正在阻塞操作的close方法,才能夠正常退出。

interrupt系列使用時候一定要注意,會引入bug,甚至死鎖。

異常處理

java中會拋出兩種異常。一種是必須要捕獲的,比如InterruptedException,否則無法通過編譯;另外一種是可以處理也可以不處理的,比如NullPointerException等。

在我們的任務運行中,很有可能拋出這兩種異常。對于第一種異常,是必須放在try,catch中的。但第二種異常如果不去處理的話,會影響任務的正常運行。

有很多同學在處理循環的任務時,沒有捕獲一些隱式的異常,造成任務在遇到異常的情況下,并不能繼續執行下去。如果不能確定異常的種類,可以直接捕獲Exception或者更通用的Throwable。

while(!isInterrupted()){ try{ …… }catch(Exception ex){ …… }}

同步方式

java中實現同步的方式有很多,大體分為以下幾種。

  • synchronized 關鍵字
  • wait、notify等
  • Concurrent包中的ReentrantLock
  • volatile關鍵字
  • ThreadLocal局部變量

生產者、消費者是wait、notify最典型的應用場景,這些函數的調用,是必須要放在synchronized代碼塊里才能夠正常運行的。它們同信號量一樣,大多數情況下屬于炫技,對代碼的可讀性影響較大,不推薦。關于ObjectMonitor相關的幾個函數,只要搞懂下面的圖,就基本ok了。

JAVA,多線程,使用場景

使用ReentrantLock最容易發生錯誤的就是忘記在finally代碼塊里關閉鎖。大多數同步場景下,使用Lock就足夠了,而且它還有讀寫鎖的概念進行粒度上的控制。我們一般都使用非公平鎖,讓任務自由競爭。非公平鎖性能高于公平鎖性能,非公平鎖能更充分的利用cpu的時間片,盡量的減少cpu空閑的狀態時間。非公平鎖還會造成餓死現象:有些任務一直獲取不到鎖。

synchronized通過鎖升級機制,速度不見得就比lock慢。而且,通過jstack,能夠方便的看到其堆棧,使用還是比較廣泛。

volatile總是能保證變量的讀可見,但它的目標是基本類型和它鎖的基本對象。假如是它修飾的是集合類,比如Map,那么它保證的讀可見是map的引用,而不是map對象,這點一定要注意。

synchronized和volatile都體現在字節碼上(monitorenter、monitorexit),主要是加入了內存屏障。而Lock,是純粹的java api。

ThreadLocal很方便,每個線程一份數據,也很安全,但要注意內存泄露。假如線程存活時間長,我們要保證每次使用完ThreadLocal,都調用它的remove()方法(具體來說是expungeStaleEntry),來清除數據。

關于Concurrent包

concurrent包是在AQS的基礎上搭建起來的,AQS提供了一種實現阻塞鎖和一系列依賴FIFO等待隊列的同步器的框架。

線程池

最全的線程池大概有7個參數,想要合理使用線程池,肯定不會不會放過這些參數的優化。

線程池參數

concurrent包最常用的就是線程池,平常工作建議直接使用線程池,Thread類就可以降低優先級了。我們常用的主要有newSingleThreadExecutor、newFixedThreadPool、newCachedThreadPool、調度等,使用Executors工廠類創建。

newSingleThreadExecutor可以用于快速創建一個異步線程,非常方便。而newCachedThreadPool永遠不要用在高并發的線上環境,它用的是無界隊列對任務進行緩沖,可能會擠爆你的內存。

我習慣性自定義ThreadPoolExecutor,也就是參數最全的那個。

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) 

假如我的任務可以預估,corePoolSize,maximumPoolSize一般都設成一樣大的,然后存活時間設的特別的長??梢员苊饩€程頻繁創建、關閉的開銷。I/O密集型和CPU密集型的應用線程開的大小是不一樣的,一般I/O密集型的應用線程就可以開的多一些。

threadFactory我一般也會定義一個,主要是給線程們起一個名字。這樣,在使用jstack等一些工具的時候,能夠直觀的看到我所創建的線程。

監控

高并發下的線程池,最好能夠監控起來??梢允褂萌罩尽⒋鎯Φ确绞奖4嫦聛?,對后續的問題排查幫助很大。

通常,可以通過繼承ThreadPoolExecutor,覆蓋beforeExecute、afterExecute、terminated方法,達到對線程行為的控制和監控。

線程池飽和策略

最容易被遺忘的可能就是線程的飽和策略了。也就是線程和緩沖隊列的空間全部用完了,新加入的任務將如何處置。jdk默認實現了4種策略,默認實現的是AbortPolicy,也就是直接拋出異常。下面介紹其他幾種。

DiscardPolicy 比abort更加激進,直接丟掉任務,連異常信息都沒有。

CallerRunsPolicy 由調用的線程來處理這個任務。比如一個web應用中,線程池資源占滿后,新進的任務將會在tomcat線程中運行。這種方式能夠延緩部分任務的執行壓力,但在更多情況下,會直接阻塞主線程的運行。

DiscardOldestPolicy 丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程)。

很多情況下,這些飽和策略可能并不能滿足你的需求,你可以自定義自己的策略,比如將任務持久化到一些存儲中。

阻塞隊列

阻塞隊列會對當前的線程進行阻塞。當隊列中有元素后,被阻塞的線程會自動被喚醒,這極大的提高的編碼的靈活性,非常方便。在并發編程中,一般推薦使用阻塞隊列,這樣實現可以盡量地避免程序出現意外的錯誤。阻塞隊列使用最經典的場景就是socket數據的讀取、解析,讀數據的線程不斷將數據放入隊列,解析線程不斷從隊列取數據進行處理。

ArrayBlockingQueue對訪問者的調用默認是不公平的,我們可以通過設置構造方法參數將其改成公平阻塞隊列。

LinkedBlockingQueue隊列的默認最大長度為Integer.MAX_VALUE,這在用做線程池隊列的時候,會比較危險。

SynchronousQueue是一個不存儲元素的阻塞隊列。每一個put操作必須等待一個take操作,否則不能繼續添加元素。隊列本身不存儲任何元素,吞吐量非常高。對于提交的任務,如果有空閑線程,則使用空閑線程來處理;否則新建一個線程來處理任務”。它更像是一個管道,在一些通訊框架中(比如rpc),通常用來快速處理某個請求,應用較為廣泛。

DelayQueue是一個支持延時獲取元素的無界阻塞隊列。放入DelayQueue的對象需要實現Delayed接口,主要是提供一個延遲的時間,以及用于延遲隊列內部比較排序。這種方式通常能夠比大多數非阻塞的while循環更加節省cpu資源。

另外還有PriorityBlockingQueue和LinkedTransferQueue等,根據字面意思就能猜測它的用途。在線程池的構造參數中,我們使用的隊列,一定要注意其特性和邊界。比如,即使是最簡單的newFixedThreadPool,在某些場景下,也是不安全的,因為它使用了無界隊列。

CountDownLatch

假如有一堆接口A-Y,每個接口的耗時最大是200ms,最小是100ms。

我的一個服務,需要提供一個接口Z,調用A-Y接口對結果進行聚合。接口的調用沒有順序需求,接口Z如何在300ms內返回這些數據?

此類問題典型的還有賽馬問題,只有通過并行計算才能完成問題。歸結起來可以分為兩類:

  • 實現任務的并行性
  • 開始執行前等待n個線程完成任務

在concurrent包出現之前,需要手工的編寫這些同步過程,非常復雜?,F在就可以使用CountDownLatch和CyclicBarrier進行便捷的編碼。

CountDownLatch是通過一個計數器來實現的,計數器的初始值為線程的數量。每當一個線程完成了自己的任務后,計數器的值就會減1。當計數器值到達0時,它表示所有的線程已經完成了任務,然后在閉鎖上等待的線程就可以恢復執行任務。

CyclicBarrier與其類似,可以實現同樣的功能。不過在日常的工作中,使用CountDownLatch會更頻繁一些。

信號量

Semaphore雖然有一些應用場景,但大部分屬于炫技,在編碼中應該盡量少用。

信號量可以實現限流的功能,但它只是常用限流方式的一種。其他兩種是漏桶算法、令牌桶算法。

hystrix的熔斷功能,也有使用信號量進行資源的控制。

Lock && Condition

在Java中,對于Lock和Condition可以理解為對傳統的synchronized和wait/notify機制的替代。concurrent包中的許多阻塞隊列,就是使用Condition實現的。

但這些類和函數對于初中級碼農來說,難以理解,容易產生bug,應該在業務代碼中嚴格禁止。但在網絡編程、或者一些框架類工程中,這些功能是必須的,萬不可將這部分的工作隨便分配給某個小弟。

End

不管是wait、notify,還是同步關鍵字或者鎖,能不用就不用,因為它們會引發程序的復雜性。最好的方式,是直接使用concurrent包所提供的機制,來規避一些編碼方面的問題。

concurrent包中的CAS概念,在一定程度上算是無鎖的一種實現。更專業的有類似disruptor的無鎖隊列框架,但它依然是建立在CAS的編程模型上的。近些年,類似AKKA這樣的事件驅動模型正在走紅,但編程模型簡單,不代表實現簡單,背后的工作依然需要多線程去協調。

golang引入協程(coroutine)概念以后,對多線程加入了更加輕量級的補充。java中可以通過javaagent技術加載quasar補充一些功能,但我覺得你不會為了這丁點效率去犧牲編碼的可讀性。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩一区二区三区在线免费观看| 国产精品视频久| 日韩在线观看成人| 欧美色另类天堂2015| 国产精品极品美女在线观看免费| 国产香蕉一区二区三区在线视频| 国产精品久久久久久久久影视| 欧美专区日韩视频| 美女999久久久精品视频| xxxx性欧美| 国产精品亚洲片夜色在线| 亚洲第一精品久久忘忧草社区| 国产精品一区久久久| 91国在线精品国内播放| 国产精品色午夜在线观看| 九九视频这里只有精品| 黑丝美女久久久| 亚洲精品一区二区久| 国产精品久久久久久久久久久久久| 欧美性猛交xxxx免费看久久久| 综合国产在线观看| 国产欧美精品一区二区三区-老狼| 亚洲品质视频自拍网| 精品小视频在线| 久久精品国产精品亚洲| 亚洲国产精品yw在线观看| 欧美丰满少妇xxxx| 亚洲电影免费观看高清| 欧美激情一区二区三级高清视频| 亚洲免费人成在线视频观看| 91美女片黄在线观| 亚洲精品国产免费| 性欧美亚洲xxxx乳在线观看| 亚洲国产成人精品一区二区| 国产精品视频99| 中文字幕成人在线| 亚洲男人天堂2019| 午夜精品一区二区三区在线播放| 亚洲国产精品中文| 色777狠狠综合秋免鲁丝| 亚洲欧美中文日韩v在线观看| 在线看片第一页欧美| 亚洲午夜av久久乱码| 日本乱人伦a精品| 日韩在线视频免费观看高清中文| 欧美壮男野外gaytube| 在线视频日本亚洲性| 日本久久久久久| 精品亚洲精品福利线在观看| 尤物99国产成人精品视频| 欧美激情网站在线观看| 亚洲经典中文字幕| 精品国偷自产在线视频| 久久精品99国产精品酒店日本| 久久国产精品影片| 日本伊人精品一区二区三区介绍| 最新91在线视频| 国产精品老女人视频| 亚洲天堂av电影| 亚洲精品成a人在线观看| 欧美成人免费全部观看天天性色| 亚洲欧美日韩精品久久奇米色影视| 97成人精品区在线播放| 国产精品亚洲第一区| 中文国产成人精品| 亚洲性线免费观看视频成熟| 伦理中文字幕亚洲| 亚洲韩国青草视频| 国产精品久久久久久久久久免费| 日韩视频在线观看免费| 亚洲人成电影网站色www| 欧美视频免费在线观看| 精品久久久久久久久久久| 91久久久久久久| 精品久久久精品| 色综合91久久精品中文字幕| 麻豆精品精华液| 不卡av日日日| 91在线免费看网站| 久久国产精品久久精品| 中文字幕在线观看日韩| 中文字幕在线精品| 美女精品视频一区| 久久久欧美一区二区| 亚洲成人免费在线视频| 欧美成人免费va影院高清| 精品日本美女福利在线观看| 亚洲日本欧美中文幕| 国产精品九九九| 国产玖玖精品视频| 午夜免费久久久久| 在线视频精品一| 欧美色图在线视频| 日本中文字幕不卡免费| 中文字幕视频在线免费欧美日韩综合在线看| 日韩国产一区三区| 久久天天躁夜夜躁狠狠躁2022| 亚洲免费中文字幕| 亚洲国产精品久久久久秋霞不卡| 中文字幕精品久久| 在线观看日韩欧美| 久久免费视频在线| 中文字幕亚洲激情| 久久久成人的性感天堂| 91精品中文在线| 岛国av在线不卡| 日韩中文字幕在线| 色琪琪综合男人的天堂aⅴ视频| 国产精品久久久久久久天堂| 77777少妇光屁股久久一区| 久久九九精品99国产精品| 国产成人短视频| 色小说视频一区| 亚洲一区二区久久久久久| 国产亚洲精品综合一区91| 国产91色在线|| 黄色成人av在线| 国产精品尤物福利片在线观看| 日韩精品免费在线观看| 成人免费在线视频网址| 欧美久久精品午夜青青大伊人| 国产成人精品视频在线观看| 国产精品视频在线观看| 国产成人在线亚洲欧美| 91精品久久久久久久久青青| 国产精品福利久久久| 欧美肥老妇视频| 亚洲国产欧美一区| 日本久久91av| 精品福利在线看| 中文字幕日韩专区| 九九精品视频在线| 欧美日韩午夜视频在线观看| 国产精品入口免费视| 国产精品99蜜臀久久不卡二区| 亚洲女人初尝黑人巨大| 高清欧美性猛交xxxx| 97精品在线视频| 欧美激情在线一区| 在线精品播放av| 久久精品视频99| 亚洲韩国青草视频| 青青久久aⅴ北条麻妃| 综合网日日天干夜夜久久| 视频在线观看一区二区| 久久久人成影片一区二区三区观看| 日韩毛片中文字幕| 中文字幕视频一区二区在线有码| 欧美午夜激情在线| 日韩女优人人人人射在线视频| 日本三级久久久| 亚洲第一区在线| 成人午夜在线观看| 中文国产成人精品久久一| 亚洲成人a**站| 欧美激情精品久久久久久黑人| 国产精品99久久久久久久久久久久| 久久久精品影院| 国产不卡av在线免费观看| 亚洲精品中文字| 欧美精品久久久久a| 欧美乱大交xxxxx另类电影| 亚洲一区www| 欧美黑人一级爽快片淫片高清|