我有这样的事情:
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 :(得分: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()
来执行此操作,但是如果其中一个which is permitted,天真的方式可能会让你陷入困境1}}调用抛出未经检查的异常({{3}}):
lock()
另一种方法是以递归方式执行,但它会增加堆栈长度的条带数量,因此如果您有大量条纹,则可以获得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