可重入锁 不可重入锁_什么是可重入锁?
可重入鎖 不可重入鎖
在Java 5.0中,增加了一個新功能以增強內部鎖定功能,稱為可重入鎖定。 在此之前,“同步”和“易失性”是實現并發的手段。
同步使用固有鎖或監視器。 Java中的每個對象都有一個與之關聯的固有鎖。 每當線程嘗試訪問同步的塊或方法時,它都會獲取該對象的固有鎖定或監視器。 在使用靜態方法的情況下,線程獲取對類對象的鎖定。
就代碼編寫而言,內在鎖定機制是一種干凈的方法,對于大多數用例而言,它都是不錯的選擇。 那么,為什么我們需要顯式鎖的其他功能? 讓我們討論。
內部鎖定機制可能具有一些功能限制,例如:
除此之外,ReentrantLock還支持鎖輪詢和支持超時的可中斷鎖等待。 ReentrantLock還支持可配置的公平性策略,從而允許更靈活的線程調度。
讓我們看一下ReentrantLock類(實現Lock)實現的幾種方法:
void lock();void lockInterruptibly() throws InterruptedException;boolean tryLock();boolean tryLock(long time, TimeUnit unit) throws InterruptedException; .....讓我們嘗試了解這些用法,看看我們可以得到什么好處。
讓我們看一下示例代碼:
public void transferMoneyWithSync(Account fromAccount, Account toAccount,float amount) throws InsufficientAmountException {synchronized (fromAccount) {// acquired lock on fromAccount Objectsynchronized (toAccount) {// acquired lock on toAccount Objectif (amount > fromAccount.getCurrentAmount()) {throw new InsufficientAmountException("Insufficient Balance");} else {fromAccount.debit(amount);toAccount.credit(amount);}}}}在上面的transferMoney()方法中,當2個線程A和B幾乎同時嘗試轉移資金時,可能會出現死鎖。
A: transferMoney(acc1, acc2, 20); B: transferMoney(acc2, acc1 ,25);線程A可能已獲得對acc1對象的鎖定,并正在等待獲取對acc2對象的鎖定,同時線程B已獲得了對acc2對象的鎖定,并且正在等待對acc1的鎖定。 這將導致死鎖,并且必須重新啟動系統!
但是,有一種避免這種情況的方法,也就是所謂的“鎖定排序”,我個人認為這有點復雜。
ReentrantLock使用tryLock()方法實現了一種更干凈的方法。 這種方法稱為“定時和輪詢鎖定獲取”。 如果您無法獲取所有必需的鎖,釋放已獲取的鎖并重試,它可以讓您重新獲得控制權。
因此,使用tryLock我們將嘗試獲取兩個鎖,如果無法同時獲取這兩個鎖,則如果已經獲取了其中之一,則釋放它,然后重試。
public boolean transferMoneyWithTryLock(Account fromAccount,Account toAccount, float amount) throws InsufficientAmountException, InterruptedException {// we are defining a stopTimelong stopTime = System.nanoTime() + 5000;while (true) {if (fromAccount.lock.tryLock()) {try {if (toAccount.lock.tryLock()) {try {if (amount > fromAccount.getCurrentAmount()) {throw new InsufficientAmountException("Insufficient Balance");} else {fromAccount.debit(amount);toAccount.credit(amount);}} finally {toAccount.lock.unlock();}}} finally {fromAccount.lock.unlock();}}if(System.nanoTime() < stopTime)return false;Thread.sleep(100);}//while}在這里,我們實現了定時鎖,因此,如果在指定時間內無法獲取鎖,則transferMoney方法將返回失敗通知并正常退出。
我們還可以使用此概念來維護時間預算活動。
可中斷的鎖獲取允許在可取消的活動中使用鎖。
lockInterruptible方法使我們能夠嘗試獲取鎖,但可用于中斷。 所以基本上這意味著 它允許線程立即響應從另一個線程發送給它的中斷信號。
當我們要向所有等待的鎖發送KILL信號時,這將很有幫助。
讓我們看一個例子,假設我們有一條共享的行來發送消息,我們希望以這樣的方式設計它:如果另一個線程來了并且中斷了當前線程,則應該釋放鎖并執行退出或關閉操作以取消當前任務。
public boolean sendOnSharedLine(String message) throws InterruptedException{lock.lockInterruptibly();try{return cancellableSendOnSharedLine(message);} finally {lock.unlock();}}private boolean cancellableSendOnSharedLine(String message){ .......定時tryLock也可響應中斷。
在固有鎖中,獲取釋放對是塊結構的,即,無論控制如何退出該塊,始終在獲取該鎖的同一基本塊中釋放該鎖。
外在鎖提供了進行更明確控制的功能。
使用外部鎖可以更輕松地實現某些概念,例如“鎖緊皮帶”。 在哈希混和集合和鏈接列表中可以看到一些用例。
ReentrantLock構造函數提供兩個公平選項的選擇:創建非公平鎖或公平鎖。 公平鎖的線程只能在它們所要求的順序獲取鎖,而一個不公平的鎖允許鎖獲取它反過來的,這就是所謂的駁運 (打破了隊列和獲取鎖,當它變得可用)。
由于掛起和恢復線程的開銷,公平鎖定會帶來巨大的性能成本。 在某些情況下,恢復掛起的線程與實際運行之間會有明顯的延遲。 讓我們看一下情況:
A -> holds lock B -> has requested and is in suspended state waiting for A to release lock C -> requests the lock at the same time when A releases the lock, C has not yet gone to suspended state.由于C尚未處于掛起狀態,因此它有可能獲得A釋放的鎖,使用它,然后在B甚至還沒有喚醒之前釋放它。 因此,在這種情況下,不公平鎖定具有明顯的性能優勢。
內部鎖和外部鎖在內部具有相同的鎖定機制,因此性能的提高純粹是主觀的。 這取決于我們上面討論的用例。 外在鎖提供了更明確的控制機制,可以更好地處理死鎖,饑餓等。我們將在以后的博客中看到更多示例。
翻譯自: https://www.javacodegeeks.com/2013/11/what-are-reentrant-locks.html
可重入鎖 不可重入鎖
總結
以上是生活随笔為你收集整理的可重入锁 不可重入锁_什么是可重入锁?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用户身份验证最佳做法清单
- 下一篇: 梓晨是什么意思 梓晨名字含义是什么