2014-03-03 25 views
0

我有這樣的事情:緩存<K,BlockingDeque <V>>條紋<Lock>結合:如何鎖定整個緩存

private Striped<ReadWriteLock> stripes = Striped.lazyWeakReadWriteLock(STRIPES_AMOUNT); 

private final Cache<Long, BlockingDeque<Peer>> peers = CacheBuilder.newBuilder() 
    .expireAfterWrite(PEER_ACCESS_TIMEOUT_MIN, TimeUnit.MINUTES) 
    .build(); 

每次我進行高速緩存操作,我的幫助下將其鎖定stripes

示例#1寫操作]

public void removePeers(long sessionId) { 
    Lock lock = stripes.get(sessionId).writeLock(); 
    lock.lock(); 
    try { 
     peers.invalidate(sessionId); 
    } finally { 
     lock.unlock(); 
    } 
} 

例#2的讀操作]

public BlockingDeque<Peer> getPeers(long sessionId) { 
    Lock lock = stripes.get(sessionId).readLock(); 
    lock.lock(); 
    try { 
     return peers.getIfPresent(sessionId); 
    } finally { 
     lock.unlock(); 
    } 
} 

例#3 [寫操作]

public boolean addPeer(Peer peer) { 
    long key = peer.getSessionId(); 
    Lock lock = stripes.get(key).writeLock(); 
    lock.lock(); 
    try { 
     BlockingDeque<Peer> userPeers = peers.getIfPresent(key); 
     if (userPeers == null) { 
      userPeers = new LinkedBlockingDeque<Peer>(); 
      peers.put(key, userPeers); 
     } 
     return userPeers.offer(peer); 
    } finally { 
     lock.unlock(); 
    } 
} 

問題:什麼是最有效的方法來鎖定下面的方法?

/** 
* I should get the whole peers in cache 
*/ 
public BlockingDeque<Peer> getAllPeers() { 
    BlockingDeque<Peer> result = new LinkedBlockingDeque<Peer>(); 
    for (BlockingDeque<Peer> deque : peers.asMap().values()) { 
     result.addAll(deque); 
    } 
    return result; 
} 
+0

如果要鎖定整個緩存,而不是提供弱一致的視圖,則可能必須爲整個緩存添加另一個讀寫鎖。但一個不太一致的觀點可能是可以接受的。 –

+0

@LouisWasserman,但我應該如何將該單獨的r-w鎖與我的「條紋」同步。或者,也許我可以遍歷整個'條紋'並鎖定所有的鎖?你能用例子回答嗎? –

回答

1

最有效的方法是完全不鎖:)

Code Review我更新的答案:你不需要一個ReadWriteLock,因此你不需要鎖定讀取。

當您閱讀(例如在線程1中)時,您將獲得當前緩存中內容的快照。如果你有併發修改(在線程2),即使你使用的鎖,緩存的內容可能已經改變之前,線程1完成其計算和鎖不買任何東西:

Thread 1    Thread 2 
     |     | 
    getAllPeers    | 
     |     addPeer 
Do something with   | 
the Peers but not   | 
    the added one    | 
     |     | 

所以你getAllPeers()的實施情況良好。


作爲一個側面說明,如果你需要鎖定所有的條紋在Striped<Lock>,你可以使用getAt()做到這一點,但用簡單的方式可以讓你陷入困境,如果lock()調用一個拋出未檢查異常(which is permitted):

for (int i = 0, size = stripes.size(); i++; i < size) { 
    stripes.getAt(i).lock(); 
} 
try { 
    // Do something 
} finally { 
    for (int i = 0, size = stripes.size(); i++; i < size) { 
     stripes.getAt(i).unlock(); 
    } 
} 

另一種方法是遞歸做到這一點,但它增加了棧的條數的長度,這樣你就可以得到一個StackOverflowException如果你有大量的條紋:

public void doSomethingWithLocks() { 
    doSomethingWithLock(0); 
} 

private void doSomethingWithLock(int stripe) { 
    if (stripe < stripes.size()) { 
     Lock lock = stripes.getAt(stripe); 
     lock.lock(); 
     try { 
      doSomethingWithLock(stripe + 1); 
     } finally { 
      lock.unlock(); 
     } 
    } else { 
     doSomething(); 
    } 
} 

private void doSomething() { 
    // Do something 
} 
+0

謝謝,非常清楚 –

相關問題