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