Récemment, j'ai rencontré au travail des scénarios à haute concurrence qui nécessitent un verrouillage pour garantir l'exactitude de la logique métier, et il est nécessaire que les performances ne soient pas grandement affectées après le verrouillage. L'idée initiale est de verrouiller l' horodatage , l'identifiant et d'autres mots-clés des données pour garantir la simultanéité des différents types de traitement de données. La granularité de verrouillage fournie par la propre api de Java est trop grande et il est difficile de répondre à ces besoins en même temps, j'ai donc écrit moi-même quelques extensions simples...
S'inspirez de l'idée de segmentation de concurrentHashMap, générez d'abord un certain nombre de verrous, puis renvoyez le verrou correspondant en fonction de la clé lorsqu'il est utilisé. Il s'agit de la stratégie de verrouillage la plus simple et la plus performante parmi plusieurs implémentations, et c'est également la stratégie de verrouillage qui a finalement été adoptée. Le code est le suivant :
/** * 分段锁,系统提供一定数量的原始锁,根据传入对象的哈希值获取对应的锁并加锁 * 注意:要锁的对象的哈希值如果发生改变,有可能导致锁无法成功释放!!! */ 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() % segments); lock.lock(); } public void unlock(T key) { ReentrantLock lock = lockMap.get(key.hashCode() % segments); lock.unlock(); } }
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(); } } }
Il est dommage que, comme ConcurrentHashMap est utilisé comme conteneur de verrouillage, il ne puisse pas vraiment se débarrasser du verrou de segmentation. Les performances de ce verrou sont environ 10 % plus rapides que celles de HashLock. Code de verrouillage :
Postscript/** * 弱引用锁,为每个独立的哈希值提供独立的锁功能 */ 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; } } }
En fait, après la mise en œuvre de ces verrous à granularité fine, de nouvelles idées ont émergé. Par exemple, les données peuvent être soumises à des threads spécialisés pour être traitées par segmentation, ce qui peut réduire le temps de blocage d'un grand nombre de threads et. laissez-le au futur Explorez…
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!