缓存<k,blockingdeque <v =“”>&gt;结合Striped <lock>:如何锁定整个缓存</lock> </k,>

时间:2014-03-03 19:59:16

标签: java multithreading concurrency guava

我有这样的事情:

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;
}

1 个答案:

答案 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