몇 가지 JAVA 세립도 자물쇠의 실현 방식
1. 세그먼트 자물쇠
concurrentHashMap의 단락 사상을 참고하여 선생은 일정한 수량의 자물쇠를 만들고 구체적으로 사용할 때 키에 따라 대응하는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. 약한 인용 자물쇠해시 자물쇠는 자물쇠의 생성과 소각의 동기화를 보장하기 위해 도입된 세그먼트 자물쇠 때문에 항상 약간의 흠이 느껴지기 때문에 세 번째 자물쇠를 써서 더욱 좋은 성능과 세립도의 자물쇠를 찾았다.이 자물쇠의 사상은 자물쇠의 약자를 빌려 자물쇠를 만들고 자물쇠의 소각을 jvm의 쓰레기 회수에 맡겨 추가 소모를 피하는 것이다.
아쉬운 점은 Concurrent Hash Map을 자물쇠로 하는 용기를 사용했기 때문에 진정한 의미에서 세그먼트 자물쇠에서 벗어나지 못했다는 점이다.이 자물쇠의 성능은 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를 빌려 세립도 자물쇠를 실현하려고 했는데 실현되고 있는 것을 발견한 것과 자바의 원생 자물쇠의 차이가 크지 않다고 쓰여 있어서 자바의 자물쇠에 대한 봉인으로 바꾸는 것을 포기하고 많은 시간을 낭비했다.
실제로 이러한 세립도 자물쇠를 실현한 후에 새로운 생각이 생겼다. 예를 들어 단락 사상을 통해 데이터를 전문적인 라인에 제출하여 처리할 수 있고 대량의 라인의 막힘 시간을 줄일 수 있으며 나중에 탐색할 수 있다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
38. Java의 Leetcode 솔루션텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.