Java中JUC包(java.util.concurrent)下的常用子類
一、對象鎖juc.locks包
在Java中除了synchronized關(guān)鍵字可以實現(xiàn)對象鎖之外,java.util.concurrent中的Lock接口也可以實現(xiàn)對象鎖。

介紹一下這個lock鎖的簡要實現(xiàn):
- JDK1.0就有的,需要JVM借助操作系統(tǒng)提供的mutex系統(tǒng)原語實現(xiàn)
- JDK1.5之后,Java語言自己實現(xiàn)的互斥鎖實現(xiàn),不需要借助操作系統(tǒng)的monitor機(jī)制。
注:使用Lock接口需要顯式的進(jìn)行加鎖和解鎖操作。
我們可以使用Lock接口的實現(xiàn)子類ReentrantLock來進(jìn)行加鎖解鎖:
ReentrantLock 可重入互斥鎖. 和 synchronized 定位類似, 都是用來實現(xiàn)互斥效果, 保證線程安全.
ReentrantLock 的用法:
lock(): 加鎖,獲取鎖失敗的線程進(jìn)入阻塞狀態(tài),直到其他線程釋放鎖,再次競爭,死等。trylock(超時時間): 加鎖, 獲取鎖失敗的線程進(jìn)入阻塞態(tài),等待一段時間,時間過了若還未獲取到鎖恢復(fù)執(zhí)行,放棄加鎖,執(zhí)行其他代碼unlock(): 解鎖
synchronized和lock的區(qū)別:
synchronized 是Java的關(guān)鍵字, 由 JVM 實現(xiàn),需要依賴操作系統(tǒng)提供的線程互斥原語(mutex),而Lock標(biāo)準(zhǔn)庫的類和接口,其中一個最常用的子類( ReentrantLock ,可重入鎖),由Java本身實現(xiàn)的,不需要依賴操作系統(tǒng)。
synchronized 隱式的加鎖和解鎖,lock需要顯示進(jìn)行加鎖和解鎖
synchronized 在獲取鎖失敗的線程時,死等;lock可以使用trylock等待一段時間之后自動放棄加鎖,線程恢復(fù)執(zhí)行

synchronized 是非公平鎖, ReentrantLock 默認(rèn)是非公平鎖. 可以通過構(gòu)造方法傳入一個 true 開啟公平鎖模式.

synchronized不支持讀寫鎖,Lock子類ReentrantReadWriteLock支持讀寫鎖。

更強(qiáng)大的喚醒機(jī)制. synchronized 是通過 Object 的 wait / notify 實現(xiàn)等待-喚醒. 每次喚醒的是一個隨機(jī)等待的線程.ReentrantLock搭配 Condition 類實現(xiàn)等待-喚醒, 可以更精確控制喚醒某個指定的線程
小結(jié):
一般場景synchronized足夠用了,需要用超時等待鎖,公平鎖,讀寫鎖再考慮使用juc.lock
如何選擇使用哪個鎖?
- 鎖競爭不激烈的時候, 使用 synchronized, 效率更高, 自動釋放更方便.
- 鎖競爭激烈的時候, 使用 ReentrantLock, 搭配 trylock 更靈活控制加鎖的行為, 而不是死等.
- 如果需要使用公平鎖, 使用 ReentrantLock.
二、原子類
原子類內(nèi)部用的是 CAS 實現(xiàn),所以性能要比加鎖實現(xiàn) i++ 高很多。原子類有以下幾個:
- AtomicBoolean
- AtomicInteger
- AtomicIntegerArray
- AtomicLong
- AtomicReference
- AtomicStampedReference
以 AtomicInteger 舉例,常見方法有:
addAndGet(int delta); i += delta; decrementAndGet(); --i; getAndDecrement(); i--; incrementAndGet(); ++i; getAndIncrement(); i++;
三、四個常用工具類
juc包下一共有四個常用工具類:
- 信號量 - Semaphore
- 計數(shù)器 - CountDownLatch
- 循環(huán)柵欄 - CyclicBarrier
- 兩個線程之間的交換器 - Exchanger
3.1 信號量 Semaphore
信號量Semaphore就是一個計數(shù)器,表示當(dāng)前可用資源的個數(shù)
關(guān)于信號量Semaphore有兩個核心操作:
- P - 申請資源操作
- V - 釋放資源操作
Semaphore 的PV加減操作都是原子性的,再多線程場景下可以直接使用
public static void main(String[] args) {
// 在構(gòu)造參數(shù)傳入可用資源的個數(shù)
// 可用資源為6個
Semaphore semaphore = new Semaphore(6);
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "準(zhǔn)備申請資源");
// P操作,每次申請兩個資源
semaphore.acquire(2);
System.out.println(Thread.currentThread().getName() + "獲取資源成功");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "釋放資源");
// V操作,默認(rèn)釋放一個占有的資源
semaphore.release(2);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 20; i++) {
Thread t = new Thread(runnable,String.valueOf(i + 1));
t.start();
}
}
3.2 CountDownLatch
有點類似于大號的join方法
調(diào)用await方法的線程需要等待其他線程將計數(shù)器減為0才能繼續(xù)恢復(fù)執(zhí)行。
public static void main(String[] args) throws InterruptedException {
// 等待線程需要等待的線程數(shù),必須等這10個子線程全部執(zhí)行完畢再恢復(fù)執(zhí)行
CountDownLatch latch = new CountDownLatch(10);
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println(Thread.currentThread().getName() + "到達(dá)終點");
// 計數(shù)器 - 1
latch.countDown();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 10; i++) {
Thread t = new Thread(runnable,"運(yùn)動員" + i + 1);
t.start();
}
// main線程就是裁判線程,需要等待所有運(yùn)動員到底終點再恢復(fù)執(zhí)行
// 直到所有線程調(diào)用countdown方法將計數(shù)器減為0繼續(xù)執(zhí)行
latch.await();
System.out.println("比賽結(jié)束~最終獲勝的是鵬哥,有請冠軍給大家高歌一首~");
}
總結(jié)
至于CyclicBarrier和Exchanger在本篇就不多介紹,讀者可以自行查閱一下官方文檔進(jìn)行仔細(xì)的學(xué)習(xí)~如果有問題可以私信博主,別忘了點贊收藏+關(guān)注哦!
相關(guān)文章
SpringBoot生產(chǎn)環(huán)境打包如何去除無用依賴
這篇文章主要介紹了SpringBoot生產(chǎn)環(huán)境打包如何去除無用依賴問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
JAVA微信掃碼支付模式二線上支付功能實現(xiàn)以及回調(diào)
本篇文章主要介紹了JAVA微信掃碼支付模式二線上支付功能實現(xiàn)以及回調(diào),這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下。2016-11-11
Java方法參數(shù)是引用調(diào)用還是值調(diào)用?
Java方法參數(shù)是引用調(diào)用還是值調(diào)用?這是一個值得思考的問題。閱讀本文,找出答案2016-02-02
SpringBoot程序的打包與運(yùn)行的實現(xiàn)
本文主要介紹了SpringBoot程序的打包與運(yùn)行的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Java實現(xiàn)ATM銀行管理系統(tǒng)(控制臺版本)
這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實現(xiàn)控制臺版本的ATM銀行管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-06-06
JavaWeb Spring依賴注入深入學(xué)習(xí)
這篇文章主要為大家詳細(xì)介紹了JavaWeb Spring依賴注入,深入學(xué)習(xí)Spring依賴注入,感興趣的小伙伴們可以參考一下2016-09-09

