java 細粒度的鎖
阿新 • • 發佈:2018-12-04
private KeyLock<String> lock = new KeyLock<String>();
lock.lock(request.getSession().getId());
finally {
lock.unlock(session.getId());
}
public class KeyLock<K>{ // 儲存所有鎖定的KEY及其訊號量 private final ConcurrentMap<K, Semaphore> map = new ConcurrentHashMap<K, Semaphore>(); // 儲存每個執行緒鎖定的KEY及其鎖定計數 private final ThreadLocal<Map<K, LockInfo>> local = new ThreadLocal<Map<K, LockInfo>>() { @Override protected Map<K, LockInfo> initialValue() { return new HashMap<K, LockInfo>(); } }; /** * 鎖定key,其他等待此key的執行緒將進入等待,直到呼叫{@link #unlock(K)} * 使用hashcode和equals來判斷key是否相同,因此key必須實現{@link #hashCode()}和 * {@link #equals(Object)}方法 * * @param key */ public void lock(K key) { if (key == null) return; LockInfo info = local.get().get(key); if (info == null) { Semaphore current = new Semaphore(1); current.acquireUninterruptibly(); Semaphore previous = map.put(key, current); if (previous != null) previous.acquireUninterruptibly(); local.get().put(key, new LockInfo(current)); } else { info.lockCount++; } } /** * 釋放key,喚醒其他等待此key的執行緒 * @param key */ public void unlock(K key) { if (key == null) return; LockInfo info = local.get().get(key); if (info != null && --info.lockCount == 0) { info.current.release(); map.remove(key, info.current); local.get().remove(key); } } /** * 鎖定多個key * 建議在呼叫此方法前先對keys進行排序,使用相同的鎖定順序,防止死鎖發生 * @param keys */ public void lock(K[] keys) { if (keys == null) return; for (K key : keys) { lock(key); } } /** * 釋放多個key * @param keys */ public void unlock(K[] keys) { if (keys == null) return; for (K key : keys) { unlock(key); } } private static class LockInfo { private final Semaphore current; private int lockCount; private LockInfo(Semaphore current) { this.current = current; this.lockCount = 1; } } }