2015-09-29 264 views
1

我有一個服務bean,它提供對Map的訪問。有時我需要重建地圖的內容,這需要幾秒鐘的時間,我想在重建時阻止對地圖的訪問,因爲它可以從不同的線程訪問。比while(reentrantLock.isLocked())更好的解決方案等待

@Service 
public class MyService { 
    private Map<Key,Value> cache = null; 
    private ReentrantLock reentrantLock = new ReentrantLock(); 

    public void rebuildCache(){ 
    try { 
     reentrantLock.lock(); 
     cache = new ConcurrentHashMap<>(); 
     ... //processing time consuming stuff and building up the cache 
     }finally { 
     reentrantLock.unlock(); 
    } 
    } 

    public Value getValue(Key key){ 
    while (lock.isLocked()){} 
    return cache.get(key); 
    } 
    ... 
} 

正如你可以看到我使用

while (reentrantLock.isLocked()){} 

檢查,如果鎖被鎖定,等待其解鎖。這個解決方案似乎很髒。有更好的解決方案嗎?

謝謝。菲爾

+0

看看FutureTask。 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/FutureTask.html – Kiki

+1

爲什麼我們不使用lock.lock(); – matt

回答

1

改爲使用ReentrantReadWriteLock

在你寫的方法:

theLock.writeLock().lock(); 
try { 
    // update the map 
} finally { 
    theLock.writeLock().unlock(); 

}

在讀法,(),而不是使用.readLock。

但問題是,在更新地圖的過程中,所有的閱讀器都會被封鎖;另一種解決方案是使用普通鎖來將舊地圖的引用替換爲新的更新的地圖,並使用普通舊的​​。


更重要的是,您使用的鎖不正確。你應該這樣做:

theLock.lock(); 
try { 
    // whatever 
} finally { 
    theLock.unlock(); 
} 

試想一下,如果鎖定失敗,當前的鎖會發生什麼:你總是試圖解開,你就會有IllegalLockStateException結束。

+0

好的謝謝。這正是我所期待的。並感謝你的第二個建議。 –

1

我會提議一個ReadWriteLock。 只要讀鎖沒有鎖定,使用它您可以隨意多次讀取。

@Service 
public class MyService { 
    private Map<Key,Value> cache = null; 
    private ReentrantLock reentrantLock = new ReentrantLock(); 

    public void rebuildCache(){ 
    try { 
     reentrantLock.writeLock().lock(); 
     cache = new ConcurrentHashMap<>(); 
     ... //processing time consuming stuff and building up the cache 
     }finally { 
     reentrantLock.writeLock().unlock(); 
    } 
    } 

    public Value getValue(Key key){ 
    if(reentrantLock.getReadLock().lock()){ 
    return cache.get(key); 
    }finally{ 
     reentrantLock.getReadLock().unlock(); 
    } 
    } 
    ... 
} 
相關問題