在寫併發代碼來提升性能時,會遵循某些最佳寫法,而不是隻用基礎的wait和notify來控制複雜的流程。
Java.util.concurrent 包是專為 Java併發編程而設計的包,它下有很多編寫好的工具,使用這些更高等的同步工具來編寫代碼,讓我們的程序可以不費力氣就得到優化。這些工具還在由一些優秀的工程師不斷優化和完善,我們不必重複造輪子:
這篇文章講述思維導圖的工具類部分:
- ReentrantLock
- Condition
- Semaphore
- ReentrantReadWriteLock
- CountDownLatch
- CyclicBarrrer
1.ReentrantLock
1.1可重入
單線程可以重複進入,但必須重複退出。
一個線程拿到幾個許可,就得釋放幾次,不然就造成線程等待,可在命令行查看等待的線程:jps -->jstack [ option ] pid
1.2可中斷
長期線程在鎖上等待問題,可以通過中斷來解決:
可在命令行查看死鎖:jps -->jstack [ option ] pid
1.3可限時
可限時也是一個避免永久等待構成死鎖的解決方法:
1.4公平鎖
先來的線程先得到鎖,如果先來的線程一直拿不到鎖,則會產生飢餓現象,公平鎖雖然不會產生飢餓現象,排隊會導致程序效率差。通過閱讀ReentrantLock的源碼發現:默認是非公平的,如果傳入true,則是公平鎖:
2.Condition
Condition與ReentrantLock的關係就類似於synchronized與Object.wait()/notify()。但是它與ReentrantLock結合使用,有await和signal與之對應.
利用Condition實現順序執行:
3.Semaphore
翻譯為信號量,允許多個線程進入臨界區。說白了就是一個廣義上的鎖,相當於共享鎖。比如信號量中我可以給它指定10個許可,每一個許可可以分配給若干個線程(當然一個線程也可以拿多個許可),拿到許可線程可以執行,如果許可分發完了,後面的線程就和鎖一樣去做等待。換句話說,當信號量等於1的時候,就相當於一把鎖。
比如早期做限流時,我們系統是8核cpu,設置同時請求任務為8個,超過8個,可以用信號量讓線程等待來加以控制:
4.ReentrantReadWriteLock
ReentrantReadWriteLock,首先要做的是與ReentrantLock劃清界限, 它和後者都是單獨的實現,彼此之間沒有繼承或實現的關係。讀寫鎖可以很好的提高程序效率,如果讀也加鎖的話,每次只有一個線程能訪問,不符合高併發程序設計。ReentrantLock和synchronized都屬於阻塞的並行,會把線程掛起,而ReadWriteLock屬於無等待的併發。
訪問情況:讀讀共享,讀寫互斥,寫寫互斥
5.CountDownLatch
實際開發中經常用於監聽某些初始化操作,等待初始化完成後,通知主線程繼續工作,它相當於一個柵欄
測試代碼:
6.CyclicBarrrer
倒數計時器。假設有一個場景:每個線程代表一個跑步運動員,當運動員都準備好後,才能一起出發,只要有一個人沒有準備好,大家都等待:
系列:
【JDK併發包基礎】線程池詳解
【JDK併發包基礎】併發容器詳解
【JDK併發包基礎】工具類詳解
閱讀更多 Java是最好的語言NO1 的文章