java并發(fā)鎖的實(shí)現(xiàn)
ReentrantLock
ReentrantLock是Java并發(fā)編程中的一種鎖機(jī)制。它的基本流程如下:
- 創(chuàng)建ReentrantLock對(duì)象。
- 在需要加鎖的代碼塊前調(diào)用lock()方法,該方法會(huì)嘗試獲取鎖,如果鎖已被其他線程占用,則當(dāng)前線程會(huì)被阻塞。
- 執(zhí)行需要加鎖的代碼。
- 在加鎖代碼塊的finally語句塊中調(diào)用unlock()方法來釋放鎖。
ReentrantLock的特點(diǎn)和用法如下:
- 可重入性:ReentrantLock是可重入鎖,即同一個(gè)線程可以重復(fù)獲取該鎖,而不會(huì)發(fā)生死鎖。這是通過維護(hù)一個(gè)持有鎖的線程的引用計(jì)數(shù)來實(shí)現(xiàn)的。
- 公平性:ReentrantLock可以指定是公平鎖還是非公平鎖,默認(rèn)情況下是非公平鎖。公平鎖是按照線程申請(qǐng)鎖的順序來分配鎖,而非公平鎖則是隨機(jī)分配鎖,可能會(huì)導(dǎo)致某些線程饑餓。
- 條件變量:ReentrantLock提供了Condition接口的實(shí)現(xiàn),可以通過該接口實(shí)現(xiàn)對(duì)線程的等待和喚醒機(jī)制,更靈活地控制線程的同步。
- 可中斷:ReentrantLock提供了lockInterruptibly()方法,如果當(dāng)前線程還沒有獲取到鎖,但是被其他線程中斷,可以通過該方法響應(yīng)中斷。
以下是一個(gè)使用ReentrantLock的Java代碼示例:
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
// 創(chuàng)建并啟動(dòng)多個(gè)線程
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new MyThread());
thread.start();
}
}
static class MyThread implements Runnable {
@Override
public void run() {
try {
// 加鎖
lock.lock();
// 執(zhí)行需要加鎖的代碼
System.out.println("Thread " + Thread.currentThread().getId() + " is running");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 釋放鎖
lock.unlock();
}
}
}
}
在上述示例中,我們創(chuàng)建了一個(gè)ReentrantLock對(duì)象,并在MyThread的run()方法中加鎖、執(zhí)行代碼、釋放鎖。在main方法中,我們創(chuàng)建并啟動(dòng)了5個(gè)線程,它們會(huì)依次獲取鎖并執(zhí)行代碼。由于ReentrantLock是可重入鎖,同一個(gè)線程可以多次獲取鎖,所以每個(gè)線程都可以成功地執(zhí)行代碼塊。
ReentrantReadWriteLock
ReentrantReadWriteLock是Java并發(fā)編程中的一個(gè)鎖機(jī)制,它是一種讀寫鎖,允許多個(gè)線程同時(shí)讀共享資源,但只能有一個(gè)線程寫資源。ReentrantReadWriteLock在實(shí)現(xiàn)上通過兩個(gè)鎖來實(shí)現(xiàn),一個(gè)是讀鎖(共享鎖),一個(gè)是寫鎖(獨(dú)占鎖)。
基本流程如下:
- 多個(gè)線程可以同時(shí)獲取讀鎖,讀鎖之間不互斥,可以并發(fā)執(zhí)行。
- 獲取寫鎖的線程會(huì)阻塞其他線程的讀鎖和寫鎖,只有釋放寫鎖后才允許其他線程獲取讀寫鎖。
ReentrantReadWriteLock的特點(diǎn)和用法:
- 公平性:可以選擇公平模式或非公平模式,默認(rèn)是非公平模式。在非公平模式下,允許鎖被后來的線程插隊(duì),以提高吞吐量;在公平模式下,鎖會(huì)按照請(qǐng)求的順序分配給線程,保證公平性。
- 重入性:與ReentrantLock一樣,ReentrantReadWriteLock可以重入,同一個(gè)線程可以多次獲取讀鎖或?qū)戞i。
- 鎖降級(jí):一個(gè)線程擁有寫鎖的時(shí)候,可以先獲取讀鎖,然后再釋放寫鎖,這樣就實(shí)現(xiàn)了鎖的降級(jí)。
- 鎖升級(jí):讀鎖不能升級(jí)為寫鎖,因?yàn)闀?huì)有死鎖的風(fēng)險(xiǎn)。
下面是一個(gè)簡(jiǎn)單的示例代碼,展示了ReentrantReadWriteLock的用法:
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MyReadWriteLock {
private int value = 0;
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public int getValue() {
lock.readLock().lock(); // 獲取讀鎖
try {
return value;
} finally {
lock.readLock().unlock(); // 釋放讀鎖
}
}
public void increment() {
lock.writeLock().lock(); // 獲取寫鎖
try {
value++;
} finally {
lock.writeLock().unlock(); // 釋放寫鎖
}
}
}
在上面的示例中,MyReadWriteLock類包含一個(gè)value變量和一個(gè)ReentrantReadWriteLock對(duì)象。getValue()方法獲取讀鎖,讀取value的值并返回。increment()方法獲取寫鎖,將value加1。通過使用讀寫鎖,多個(gè)線程可以同時(shí)讀取value的值,但只有一個(gè)線程可以寫入value的值。
Condition
Condition是Java并發(fā)編程中的一種同步機(jī)制,它可以用于實(shí)現(xiàn)線程之間的等待和通知。
基本流程:
- 創(chuàng)建一個(gè)Lock對(duì)象,通過Lock對(duì)象的newCondition()方法創(chuàng)建一個(gè)Condition對(duì)象。
- 通過Lock對(duì)象的lock()方法獲取鎖。
- 在某個(gè)線程中,通過Condition對(duì)象的await()方法使線程等待,同時(shí)釋放鎖。
- 在另一個(gè)線程中,通過Condition對(duì)象的signal()或signalAll()方法進(jìn)行通知。
- 在第一個(gè)線程中,通過Condition對(duì)象的await()方法再次獲取鎖并繼續(xù)執(zhí)行。
特點(diǎn)和用法:
- 可以與Lock對(duì)象配合使用,對(duì)某個(gè)共享資源進(jìn)行互斥訪問和條件等待。
- 可以精確地控制線程的等待和通知。
示例代碼:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionExample {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean flag = false;
public void waitForFlag() throws InterruptedException {
lock.lock();
try {
while (!flag) {
condition.await(); // 線程等待并釋放鎖
}
} finally {
lock.unlock();
}
System.out.println("Flag is true, continue executing.");
}
public void setFlag() {
lock.lock();
try {
flag = true;
condition.signalAll(); // 發(fā)送通知并喚醒等待線程
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
final ConditionExample example = new ConditionExample();
Thread waitingThread = new Thread(() -> {
try {
example.waitForFlag();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread settingThread = new Thread(() -> {
try {
Thread.sleep(2000); // 模擬執(zhí)行耗時(shí)操作
example.setFlag();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
waitingThread.start();
settingThread.start();
waitingThread.join();
settingThread.join();
}
}
在上述示例中,有兩個(gè)線程,一個(gè)線程等待flag變量為true,另一個(gè)線程在某一時(shí)刻將flag設(shè)置為true。通過Condition對(duì)象的await()方法使等待線程進(jìn)入等待狀態(tài),并釋放鎖,直到另一個(gè)線程通過Condition對(duì)象的signalAll()方法發(fā)送通知并喚醒等待線程,等待線程再次獲取鎖并繼續(xù)執(zhí)行。
應(yīng)用場(chǎng)景
不同的鎖機(jī)制應(yīng)對(duì)的問題不同,在使用時(shí)需要根據(jù)具體的應(yīng)用場(chǎng)景進(jìn)行選擇。
synchronized 鎖適用于互斥場(chǎng)景,代碼粒度小,適合在單線程或少量并發(fā)的情況下使用。
Lock 鎖適用于復(fù)雜的并發(fā)場(chǎng)景,通過支持公平性、可中斷等待鎖等特點(diǎn),提高了系統(tǒng)的性能。
ReentrantLock 鎖是 Lock 接口的實(shí)現(xiàn)類,支持可重入、可中斷等待等特點(diǎn),適用于異步線程操作。
ReadWriteLock 鎖適用于讀寫性能比較高的場(chǎng)景,在讀多寫少的情況下可以提高并發(fā)性能。
StampedLock 鎖適用于讀多寫少的場(chǎng)景,在使用時(shí)需要根據(jù)實(shí)際場(chǎng)景選擇樂觀鎖或悲觀鎖,提高了并發(fā)性能。
總結(jié)
Java并發(fā)體系中的鎖是用來管理多個(gè)線程對(duì)共享資源的訪問的工具。鎖的使用可以確保多個(gè)線程之間的同步和互斥,從而避免競(jìng)態(tài)條件和數(shù)據(jù)的不一致性。
Java中的鎖可以分為兩大類:內(nèi)置鎖和顯式鎖。
內(nèi)置鎖:
- synchronized關(guān)鍵字:synchronized是Java中最基本的內(nèi)置鎖機(jī)制。它可以修飾方法或代碼塊,一次只允許一個(gè)線程訪問被修飾的代碼塊或方法。當(dāng)一個(gè)線程獲得鎖時(shí),其他線程必須等待鎖釋放才能繼續(xù)執(zhí)行。
- 鎖對(duì)象:synchronized還可以用于指定一個(gè)對(duì)象作為鎖。當(dāng)一個(gè)線程獲得該對(duì)象的鎖時(shí),其他線程對(duì)該對(duì)象的訪問將被阻塞。這種方式可以實(shí)現(xiàn)更細(xì)粒度的鎖控制。
顯式鎖:
- ReentrantLock類:ReentrantLock是Java提供的顯式鎖的實(shí)現(xiàn)類。它提供了與synchronized類似的功能,但提供了更靈活的鎖控制。通過lock()方法獲取鎖,通過unlock()方法釋放鎖。ReentrantLock還提供了一些其他功能,如可中斷鎖、公平鎖等。
- Condition接口:Condition接口是與顯式鎖ReentrantLock配合使用的重要組件。它可以讓線程在等待某個(gè)條件滿足時(shí)暫時(shí)釋放鎖,從而避免了線程一直占用鎖資源而無法執(zhí)行其他任務(wù)。
鎖的選擇應(yīng)根據(jù)具體的需求和場(chǎng)景來決定。synchronized是最簡(jiǎn)單和常用的鎖機(jī)制,適用于大部分情況。ReentrantLock提供了更多的靈活性和高級(jí)功能,例如可中斷鎖、公平鎖等,但使用起來相對(duì)復(fù)雜一些。在多個(gè)線程需要等待某個(gè)條件滿足時(shí),使用Condition接口可以更好地控制線程的等待和喚醒。
到此這篇關(guān)于java并發(fā)鎖的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)java并發(fā)鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
快速解決jdk初始化運(yùn)行,防火墻通信選錯(cuò)專業(yè)網(wǎng)絡(luò)的問題
新項(xiàng)目添加不同JDK版本時(shí)因防火墻通信策略導(dǎo)致外部連接失敗,解決方法為調(diào)整防火墻設(shè)置,允許應(yīng)用通過并將其設(shè)為公用網(wǎng)絡(luò),適用于多JDK環(huán)境2025-08-08
從零搭建SpringBoot+MyBatisPlus快速開發(fā)腳手架
這篇文章主要為大家介紹了從零搭建SpringBoot+MyBatisPlus快速開發(fā)腳手架示例教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
springboot啟動(dòng)后卡住無日志的幾種情況小結(jié)
這篇文章主要介紹了springboot啟動(dòng)后卡住無日志的幾種情況小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
SpringBoot中項(xiàng)目結(jié)構(gòu)的項(xiàng)目實(shí)踐
SpringBoot項(xiàng)目結(jié)構(gòu)遵循Maven或Gradle的標(biāo)準(zhǔn)目錄結(jié)構(gòu),融入了SpringBoot的特定約定,本文就來介紹一下SpringBoot中項(xiàng)目結(jié)構(gòu)的項(xiàng)目,感興趣的可以了解一下2025-03-03

