java 并发锁_Java并发教程–重入锁
java 并發(fā)鎖
Java的synced關(guān)鍵字是一個(gè)很棒的工具–它使我們可以通過(guò)一種簡(jiǎn)單可靠的方式來(lái)同步對(duì)關(guān)鍵部分的訪問(wèn),而且也不難理解。但是有時(shí)我們需要對(duì)同步進(jìn)行更多控制。 我們要么需要分別控制訪問(wèn)類型(讀取和寫入),要么使用起來(lái)很麻煩,因?yàn)橐礇](méi)有明顯的互斥鎖,要么我們需要維護(hù)多個(gè)互斥鎖。
幸運(yùn)的是,在Java 1.5中添加了鎖實(shí)用程序類,使這些問(wèn)題更易于解決。
Java重入鎖
Java在java.util.concurrent.locks包中有一些鎖實(shí)現(xiàn)。
鎖的一般類很好地布置為接口:
- 鎖 –最簡(jiǎn)單的鎖,可以獲取和釋放
- ReadWriteLock –具有讀和寫鎖類型的鎖實(shí)現(xiàn)–一次可以持有多個(gè)讀鎖,除非持有排他寫鎖
Java提供了我們關(guān)心的這些鎖的兩種實(shí)現(xiàn)–兩者都是可重入的(這僅意味著線程可以多次重新獲取同一鎖而沒(méi)有任何問(wèn)題)。
- ReentrantLock –如您所料,可重入鎖實(shí)現(xiàn)
- ReentrantReadWriteLock –可重入ReadWriteLock實(shí)現(xiàn)
現(xiàn)在,讓我們看一些例子。
讀/寫鎖定示例
那么如何使用鎖呢? 這很簡(jiǎn)單:只需獲取并發(fā)布(永遠(yuǎn)不要忘記發(fā)布-終于是您的朋友!)。
假設(shè)我們有一個(gè)非常簡(jiǎn)單的情況,我們需要同步訪問(wèn)一對(duì)變量。 一個(gè)是簡(jiǎn)單的值,另一個(gè)是根據(jù)一些冗長(zhǎng)的計(jì)算得出的。 首先,這是我們?nèi)绾问褂胹ynced關(guān)鍵字執(zhí)行此操作。
public class Calculator {private int calculatedValue;private int value;public synchronized void calculate(int value) {this.value = value;this.calculatedValue = doMySlowCalculation(value);}public synchronized int getCalculatedValue() {return calculatedValue;}public synchronized int getValue() {return value;} }很簡(jiǎn)單,但是如果我們有很多爭(zhēng)用,或者執(zhí)行很多讀取而寫很少,則同步可能會(huì)影響性能。 由于頻繁讀取比寫入頻繁得多,因此使用ReadWriteLock可幫助我們最大程度地減少問(wèn)題:
public class Calculator {private int calculatedValue;private int value;private ReadWriteLock lock = new ReentrantReadWriteLock();public void calculate(int value) {lock.writeLock().lock();try {this.value = value;this.calculatedValue = doMySlowCalculation(value);} finally {lock.writeLock().unlock();}}public int getCalculatedValue() {lock.readLock().lock();try {return calculatedValue;} finally {lock.readLock().unlock();}}public int getValue() {lock.readLock().lock();try {return value;} finally {lock.readLock().unlock();}} }此示例實(shí)際上顯示了使用同步has的一大優(yōu)勢(shì):與使用顯式鎖相比,此方法簡(jiǎn)潔明了且更加安全。 但是鎖提供了使用靈活性,而這是我們以前所沒(méi)有的。
在上面的示例中,我們可以讓數(shù)百個(gè)線程一次讀取相同的值而沒(méi)有問(wèn)題,并且只有在獲得寫入鎖定時(shí)才阻塞讀取器。 請(qǐng)記住:許多讀取器可以同時(shí)獲取讀取鎖,但是在獲取寫入鎖時(shí)不允許讀取器或?qū)懭肫鳌?
更典型的用途
我們的第一個(gè)示例可能會(huì)讓您感到困惑或不完全相信顯式鎖是有用的。 難道他們還沒(méi)有其他用途嗎? 當(dāng)然!
我們?cè)贑arfey使用顯式鎖來(lái)解決許多問(wèn)題。 一個(gè)示例是您有可以同時(shí)運(yùn)行的各種任務(wù),但是您不希望同時(shí)運(yùn)行多個(gè)相同類型的任務(wù)。 一種實(shí)現(xiàn)它的干凈方法是使用鎖。 可以通過(guò)同步來(lái)完成,但是鎖使我們能夠在超時(shí)后失敗。
值得一提的是,您會(huì)注意到我們使用了同步鎖和顯式鎖的混合-有時(shí)一個(gè)比另一個(gè)更干凈,更簡(jiǎn)單。
public class TaskRunner {private Map<Class<? extends Runnable>, Lock> mLocks =new HashMap<Class<? extends Runnable>, Lock>();public void runTaskUniquely(Runnable r, int secondsToWait) {Lock lock = getLock(r.getClass());boolean acquired = lock.tryLock(secondsToWait, TimeUnit.SECONDS);if (acquired) {try {r.run();} finally {lock.unlock();}} else {// failure code here}}private synchronized Lock getLock(Class clazz) {Lock l = mLocks.get(clazz);if (l == null) {l = new ReentrantLock();mLocks.put(clazz, l);}return l;} }這兩個(gè)示例應(yīng)該使您對(duì)如何同時(shí)使用計(jì)劃鎖和ReadWriteLocks有所了解。 與同步一樣,不必?fù)?dān)心重新獲得相同的鎖-JDK中提供的鎖是可重入的,因此不會(huì)有任何問(wèn)題。
每當(dāng)您處理并發(fā)時(shí),都有危險(xiǎn)。 永遠(yuǎn)記住以下幾點(diǎn):
- 釋放所有鎖,使其最終鎖??住。 這是規(guī)則1,是有原因的。
- 當(dāng)心線程饑餓! 如果您有不想永久等待的許多讀者和偶爾的作家,那么ReentrantLocks中的公平設(shè)置可能會(huì)很有用。 如果其他線程不斷持有讀取鎖,那么編寫者有可能等待很長(zhǎng)時(shí)間(也許永遠(yuǎn))。
- 盡可能使用同步。 您將避免錯(cuò)誤并保持代碼更清潔。
- 如果您不希望線程無(wú)限期等待獲取鎖,請(qǐng)使用tryLock() -這類似于數(shù)據(jù)庫(kù)具有的等待鎖超時(shí)。
就是這樣! 如果您有任何問(wèn)題或意見(jiàn),請(qǐng)隨時(shí)將其留在下面。
參考: Java并發(fā)第2部分–來(lái)自JCG合作伙伴的Carent博客上的 Reentrant Locks 。
相關(guān)文章 :- Java并發(fā)教程–信號(hào)量
- Java并發(fā)教程–線程池
- Java并發(fā)教程–可調(diào)用,將來(lái)
- Java并發(fā)教程–阻塞隊(duì)列
- Java并發(fā)教程– CountDownLatch
- Exchanger和無(wú)GC的Java
- Java Fork / Join進(jìn)行并行編程
- Java最佳實(shí)踐–隊(duì)列之戰(zhàn)和鏈接的ConcurrentHashMap
- 使用迭代器時(shí)如何避免ConcurrentModificationException
- 改善Java應(yīng)用程序性能的快速技巧
翻譯自: https://www.javacodegeeks.com/2011/09/java-concurrency-tutorial-reentrant.html
java 并發(fā)鎖
總結(jié)
以上是生活随笔為你收集整理的java 并发锁_Java并发教程–重入锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何进入二级路由器设置如何跳转到二级路由
- 下一篇: Java数字格式:DecimalForm