幾種JAVA細粒度鎖的完成方法。本站提示廣大學習愛好者:(幾種JAVA細粒度鎖的完成方法)文章只能為提供參考,不一定能成為您想要的結果。以下是幾種JAVA細粒度鎖的完成方法正文
比來在任務上碰見了一些高並發的場景須要加鎖來包管營業邏輯的准確性,而且請求加鎖後機能不克不及遭到太年夜的影響。初步的設法主意是經由過程數據的時光戳,id等症結字來加鎖,從而包管分歧類型數據處置的並發性。而java本身api供給的鎖粒度太年夜,很難同時知足這些需求,因而本身著手寫了幾個簡略的擴大...
1. 分段鎖
自創concurrentHashMap的分段思惟,師長教師成必定數目的鎖,詳細應用的時刻再依據key來前往對應的lock。這是幾個完成裡最簡略,機能最高,也是終究被采取的鎖戰略,代碼以下:
/** * 分段鎖,體系供給必定數目的原始鎖,依據傳入對象的哈希值獲得對應的鎖並加鎖 * 留意:要鎖的對象的哈希值假如產生轉變,有能夠招致鎖沒法勝利釋放!!! */ public class SegmentLock<T> { private Integer segments = 16;//默許分段數目 private final HashMap<Integer, ReentrantLock> lockMap = new HashMap<>(); public SegmentLock() { init(null, false); } public SegmentLock(Integer counts, boolean fair) { init(counts, fair); } private void init(Integer counts, boolean fair) { if (counts != null) { segments = counts; } for (int i = 0; i < segments; i++) { lockMap.put(i, new ReentrantLock(fair)); } } public void lock(T key) { ReentrantLock lock = lockMap.get((key.hashCode()>>>1) % segments); lock.lock(); } public void unlock(T key) { ReentrantLock lock = lockMap.get((key.hashCode()>>>1) % segments); lock.unlock(); } }
2. 哈希鎖
上述分段鎖的基本上成長起來的第二種鎖戰略,目標是完成真正意義上的細粒度鎖。每一個哈希值分歧的對象都能取得本身自力的鎖。在測試中,在被鎖住的代碼履行速度飛快的情形下,效力比分段鎖慢 30% 閣下。假如有長耗時操作,感到表示應當會更好。代碼以下:
public class HashLock<T> { private boolean isFair = false; private final SegmentLock<T> segmentLock = new SegmentLock<>();//分段鎖 private final ConcurrentHashMap<T, LockInfo> lockMap = new ConcurrentHashMap<>(); public HashLock() { } public HashLock(boolean fair) { isFair = fair; } public void lock(T key) { LockInfo lockInfo; segmentLock.lock(key); try { lockInfo = lockMap.get(key); if (lockInfo == null) { lockInfo = new LockInfo(isFair); lockMap.put(key, lockInfo); } else { lockInfo.count.incrementAndGet(); } } finally { segmentLock.unlock(key); } lockInfo.lock.lock(); } public void unlock(T key) { LockInfo lockInfo = lockMap.get(key); if (lockInfo.count.get() == 1) { segmentLock.lock(key); try { if (lockInfo.count.get() == 1) { lockMap.remove(key); } } finally { segmentLock.unlock(key); } } lockInfo.count.decrementAndGet(); lockInfo.unlock(); } private static class LockInfo { public ReentrantLock lock; public AtomicInteger count = new AtomicInteger(1); private LockInfo(boolean fair) { this.lock = new ReentrantLock(fair); } public void lock() { this.lock.lock(); } public void unlock() { this.lock.unlock(); } } }
3. 弱援用鎖
哈希鎖由於引入的分段鎖來包管鎖創立和燒毀的同步,總感到有點瑕疵,所以寫了第三個鎖來追求更好的機能和更細粒度的鎖。這個鎖的思惟是借助java的弱援用來創立鎖,把鎖的燒毀交給jvm的渣滓收受接管,來防止額定的消費。
有點遺憾的是由於應用了ConcurrentHashMap作為鎖的容器,所以沒能真正意義上的解脫分段鎖。這個鎖的機能比 HashLock 快10% 閣下。鎖代碼:
/** * 弱援用鎖,為每一個自力的哈希值供給自力的鎖功效 */ public class WeakHashLock<T> { private ConcurrentHashMap<T, WeakLockRef<T, ReentrantLock>> lockMap = new ConcurrentHashMap<>(); private ReferenceQueue<ReentrantLock> queue = new ReferenceQueue<>(); public ReentrantLock get(T key) { if (lockMap.size() > 1000) { clearEmptyRef(); } WeakReference<ReentrantLock> lockRef = lockMap.get(key); ReentrantLock lock = (lockRef == null ? null : lockRef.get()); while (lock == null) { lockMap.putIfAbsent(key, new WeakLockRef<>(new ReentrantLock(), queue, key)); lockRef = lockMap.get(key); lock = (lockRef == null ? null : lockRef.get()); if (lock != null) { return lock; } clearEmptyRef(); } return lock; } @SuppressWarnings("unchecked") private void clearEmptyRef() { Reference<? extends ReentrantLock> ref; while ((ref = queue.poll()) != null) { WeakLockRef<T, ? extends ReentrantLock> weakLockRef = (WeakLockRef<T, ? extends ReentrantLock>) ref; lockMap.remove(weakLockRef.key); } } private static final class WeakLockRef<T, K> extends WeakReference<K> { final T key; private WeakLockRef(K referent, ReferenceQueue<? super K> q, T key) { super(referent, q); this.key = key; } } }
跋文
最開端想借助 locksupport 和 AQS 來完成細粒度鎖,寫著寫著發明正在完成的器械和java 原生的鎖差別不年夜,因而廢棄改成對java自帶鎖的封裝,糟蹋了很多時光。
現實上在完成了這些細粒度鎖以後,又有了新的設法主意,好比可以經由過程分段思惟將數據提交給專門的線程來處置,可以削減年夜量線程的壅塞時光,留待往後摸索...