java并發(fā)鎖的實(shí)現(xiàn)
ReentrantLock
ReentrantLock是Java并發(fā)編程中的一種鎖機(jī)制。它的基本流程如下:
- 創(chuàng)建ReentrantLock對(duì)象。
- 在需要加鎖的代碼塊前調(diào)用lock()方法,該方法會(huì)嘗試獲取鎖,如果鎖已被其他線(xiàn)程占用,則當(dāng)前線(xiàn)程會(huì)被阻塞。
- 執(zhí)行需要加鎖的代碼。
- 在加鎖代碼塊的finally語(yǔ)句塊中調(diào)用unlock()方法來(lái)釋放鎖。
ReentrantLock的特點(diǎn)和用法如下:
- 可重入性:ReentrantLock是可重入鎖,即同一個(gè)線(xiàn)程可以重復(fù)獲取該鎖,而不會(huì)發(fā)生死鎖。這是通過(guò)維護(hù)一個(gè)持有鎖的線(xiàn)程的引用計(jì)數(shù)來(lái)實(shí)現(xiàn)的。
- 公平性:ReentrantLock可以指定是公平鎖還是非公平鎖,默認(rèn)情況下是非公平鎖。公平鎖是按照線(xiàn)程申請(qǐng)鎖的順序來(lái)分配鎖,而非公平鎖則是隨機(jī)分配鎖,可能會(huì)導(dǎo)致某些線(xiàn)程饑餓。
- 條件變量:ReentrantLock提供了Condition接口的實(shí)現(xiàn),可以通過(guò)該接口實(shí)現(xiàn)對(duì)線(xiàn)程的等待和喚醒機(jī)制,更靈活地控制線(xiàn)程的同步。
- 可中斷:ReentrantLock提供了lockInterruptibly()方法,如果當(dāng)前線(xiàn)程還沒(méi)有獲取到鎖,但是被其他線(xiàn)程中斷,可以通過(guò)該方法響應(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è)線(xiàn)程 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è)線(xiàn)程,它們會(huì)依次獲取鎖并執(zhí)行代碼。由于ReentrantLock是可重入鎖,同一個(gè)線(xiàn)程可以多次獲取鎖,所以每個(gè)線(xiàn)程都可以成功地執(zhí)行代碼塊。
ReentrantReadWriteLock
ReentrantReadWriteLock是Java并發(fā)編程中的一個(gè)鎖機(jī)制,它是一種讀寫(xiě)鎖,允許多個(gè)線(xiàn)程同時(shí)讀共享資源,但只能有一個(gè)線(xiàn)程寫(xiě)資源。ReentrantReadWriteLock在實(shí)現(xiàn)上通過(guò)兩個(gè)鎖來(lái)實(shí)現(xiàn),一個(gè)是讀鎖(共享鎖),一個(gè)是寫(xiě)鎖(獨(dú)占鎖)。
基本流程如下:
- 多個(gè)線(xiàn)程可以同時(shí)獲取讀鎖,讀鎖之間不互斥,可以并發(fā)執(zhí)行。
- 獲取寫(xiě)鎖的線(xiàn)程會(huì)阻塞其他線(xiàn)程的讀鎖和寫(xiě)鎖,只有釋放寫(xiě)鎖后才允許其他線(xiàn)程獲取讀寫(xiě)鎖。
ReentrantReadWriteLock的特點(diǎn)和用法:
- 公平性:可以選擇公平模式或非公平模式,默認(rèn)是非公平模式。在非公平模式下,允許鎖被后來(lái)的線(xiàn)程插隊(duì),以提高吞吐量;在公平模式下,鎖會(huì)按照請(qǐng)求的順序分配給線(xiàn)程,保證公平性。
- 重入性:與ReentrantLock一樣,ReentrantReadWriteLock可以重入,同一個(gè)線(xiàn)程可以多次獲取讀鎖或?qū)戞i。
- 鎖降級(jí):一個(gè)線(xiàn)程擁有寫(xiě)鎖的時(shí)候,可以先獲取讀鎖,然后再釋放寫(xiě)鎖,這樣就實(shí)現(xiàn)了鎖的降級(jí)。
- 鎖升級(jí):讀鎖不能升級(jí)為寫(xiě)鎖,因?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(); // 獲取寫(xiě)鎖 try { value++; } finally { lock.writeLock().unlock(); // 釋放寫(xiě)鎖 } } }
在上面的示例中,MyReadWriteLock類(lèi)包含一個(gè)value變量和一個(gè)ReentrantReadWriteLock對(duì)象。getValue()方法獲取讀鎖,讀取value的值并返回。increment()方法獲取寫(xiě)鎖,將value加1。通過(guò)使用讀寫(xiě)鎖,多個(gè)線(xiàn)程可以同時(shí)讀取value的值,但只有一個(gè)線(xiàn)程可以寫(xiě)入value的值。
Condition
Condition是Java并發(fā)編程中的一種同步機(jī)制,它可以用于實(shí)現(xiàn)線(xiàn)程之間的等待和通知。
基本流程:
- 創(chuàng)建一個(gè)Lock對(duì)象,通過(guò)Lock對(duì)象的newCondition()方法創(chuàng)建一個(gè)Condition對(duì)象。
- 通過(guò)Lock對(duì)象的lock()方法獲取鎖。
- 在某個(gè)線(xiàn)程中,通過(guò)Condition對(duì)象的await()方法使線(xiàn)程等待,同時(shí)釋放鎖。
- 在另一個(gè)線(xiàn)程中,通過(guò)Condition對(duì)象的signal()或signalAll()方法進(jìn)行通知。
- 在第一個(gè)線(xiàn)程中,通過(guò)Condition對(duì)象的await()方法再次獲取鎖并繼續(xù)執(zhí)行。
特點(diǎn)和用法:
- 可以與Lock對(duì)象配合使用,對(duì)某個(gè)共享資源進(jìn)行互斥訪問(wèn)和條件等待。
- 可以精確地控制線(xià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(); // 線(xiàn)程等待并釋放鎖 } } finally { lock.unlock(); } System.out.println("Flag is true, continue executing."); } public void setFlag() { lock.lock(); try { flag = true; condition.signalAll(); // 發(fā)送通知并喚醒等待線(xiàn)程 } 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è)線(xiàn)程,一個(gè)線(xiàn)程等待flag變量為true,另一個(gè)線(xiàn)程在某一時(shí)刻將flag設(shè)置為true。通過(guò)Condition對(duì)象的await()方法使等待線(xiàn)程進(jìn)入等待狀態(tài),并釋放鎖,直到另一個(gè)線(xiàn)程通過(guò)Condition對(duì)象的signalAll()方法發(fā)送通知并喚醒等待線(xiàn)程,等待線(xiàn)程再次獲取鎖并繼續(xù)執(zhí)行。
應(yīng)用場(chǎng)景
不同的鎖機(jī)制應(yīng)對(duì)的問(wèn)題不同,在使用時(shí)需要根據(jù)具體的應(yīng)用場(chǎng)景進(jìn)行選擇。
synchronized 鎖適用于互斥場(chǎng)景,代碼粒度小,適合在單線(xiàn)程或少量并發(fā)的情況下使用。
Lock 鎖適用于復(fù)雜的并發(fā)場(chǎng)景,通過(guò)支持公平性、可中斷等待鎖等特點(diǎn),提高了系統(tǒng)的性能。
ReentrantLock 鎖是 Lock 接口的實(shí)現(xiàn)類(lèi),支持可重入、可中斷等待等特點(diǎn),適用于異步線(xiàn)程操作。
ReadWriteLock 鎖適用于讀寫(xiě)性能比較高的場(chǎng)景,在讀多寫(xiě)少的情況下可以提高并發(fā)性能。
StampedLock 鎖適用于讀多寫(xiě)少的場(chǎng)景,在使用時(shí)需要根據(jù)實(shí)際場(chǎng)景選擇樂(lè)觀鎖或悲觀鎖,提高了并發(fā)性能。
總結(jié)
Java并發(fā)體系中的鎖是用來(lái)管理多個(gè)線(xiàn)程對(duì)共享資源的訪問(wèn)的工具。鎖的使用可以確保多個(gè)線(xiàn)程之間的同步和互斥,從而避免競(jìng)態(tài)條件和數(shù)據(jù)的不一致性。
Java中的鎖可以分為兩大類(lèi):內(nèi)置鎖和顯式鎖。
內(nèi)置鎖:
- synchronized關(guān)鍵字:synchronized是Java中最基本的內(nèi)置鎖機(jī)制。它可以修飾方法或代碼塊,一次只允許一個(gè)線(xiàn)程訪問(wèn)被修飾的代碼塊或方法。當(dāng)一個(gè)線(xiàn)程獲得鎖時(shí),其他線(xiàn)程必須等待鎖釋放才能繼續(xù)執(zhí)行。
- 鎖對(duì)象:synchronized還可以用于指定一個(gè)對(duì)象作為鎖。當(dāng)一個(gè)線(xiàn)程獲得該對(duì)象的鎖時(shí),其他線(xiàn)程對(duì)該對(duì)象的訪問(wèn)將被阻塞。這種方式可以實(shí)現(xiàn)更細(xì)粒度的鎖控制。
顯式鎖:
- ReentrantLock類(lèi):ReentrantLock是Java提供的顯式鎖的實(shí)現(xiàn)類(lèi)。它提供了與synchronized類(lèi)似的功能,但提供了更靈活的鎖控制。通過(guò)lock()方法獲取鎖,通過(guò)unlock()方法釋放鎖。ReentrantLock還提供了一些其他功能,如可中斷鎖、公平鎖等。
- Condition接口:Condition接口是與顯式鎖ReentrantLock配合使用的重要組件。它可以讓線(xiàn)程在等待某個(gè)條件滿(mǎn)足時(shí)暫時(shí)釋放鎖,從而避免了線(xiàn)程一直占用鎖資源而無(wú)法執(zhí)行其他任務(wù)。
鎖的選擇應(yīng)根據(jù)具體的需求和場(chǎng)景來(lái)決定。synchronized是最簡(jiǎn)單和常用的鎖機(jī)制,適用于大部分情況。ReentrantLock提供了更多的靈活性和高級(jí)功能,例如可中斷鎖、公平鎖等,但使用起來(lái)相對(duì)復(fù)雜一些。在多個(gè)線(xiàn)程需要等待某個(gè)條件滿(mǎn)足時(shí),使用Condition接口可以更好地控制線(xiàn)程的等待和喚醒。
到此這篇關(guān)于java并發(fā)鎖的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)java并發(fā)鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springmvc ajax跨域請(qǐng)求處理方法實(shí)例詳解
這篇文章主要介紹了Springmvc ajax跨域請(qǐng)求處理方法實(shí)例詳解,需要的朋友可以參考下2017-10-10Java如何獲取List<String>中的String詳解
工作了這么長(zhǎng)時(shí)間了,一直沒(méi)有記錄的習(xí)慣,以至于導(dǎo)致我即便是查過(guò)的東西總會(huì)忘記,下面這篇文章主要給大家介紹了關(guān)于Java如何獲取List<String>中String的相關(guān)資料,需要的朋友可以參考下2022-02-02java開(kāi)發(fā)AOP基礎(chǔ)JdkDynamicAopProxy
這篇文章主要為大家介紹了java開(kāi)發(fā)AOP基礎(chǔ)JdkDynamicAopProxy源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07java 進(jìn)程是如何在Linux服務(wù)器上進(jìn)行內(nèi)存分配的
這篇文章主要介紹了java 進(jìn)程是如何在Linux服務(wù)器上進(jìn)行內(nèi)存分配的,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-11-11Springboot中用 Netty 開(kāi)啟UDP服務(wù)方式
這篇文章主要介紹了Springboot中用 Netty 開(kāi)啟UDP服務(wù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11MyBatis-Plus中Service接口的lambdaUpdate用法及實(shí)例分析
本文將詳細(xì)講解MyBatis-Plus中的lambdaUpdate用法,并提供豐富的案例來(lái)幫助讀者更好地理解和應(yīng)用該特性,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03java JSON解析庫(kù)Alibaba Fastjson用法詳解
這篇文章主要介紹了java JSON解析庫(kù)Alibaba Fastjson用法,結(jié)合實(shí)例形式詳細(xì)分析了java JSON解析庫(kù)Alibaba Fastjson的基本功能、原理、用法及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04BufferedReader中read()方法和readLine()方法的使用
這篇文章主要介紹了BufferedReader中read()方法和readLine()方法的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04