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

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

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

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

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

