昨天我自己编写了一个基于ZooKeeper的分布式锁,但发现出现了死锁问题。今天我打算学习Curator中的InterProcessMutex,了解如何解决死锁。
Curator使用了可重入锁来解决死锁问题。
可重入锁指的是当一个服务已经获取了某个锁后,再次请求该锁时不会被阻塞,而是需要解锁的次数加一。
private boolean internalLock(long time, TimeUnit unit) throws Exception {
Thread currentThread = Thread.currentThread();
LockData lockData = (LockData)this.threadData.get(currentThread);
if (lockData != null) {
lockData.lockCount.incrementAndGet();
return true;
} else {
String lockPath =
this.internals.attemptLock(time,unit,this.getLockNodeBytes());
if (lockPath != null) {
LockData newLockData = new LockData(currentThread, lockPath);
this.threadData.put(currentThread, newLockData);
return true;
} else {
return false;
}
}
}
在Curator的实现中,通过维护一个LockData对象来记录锁的状态,其中包括一个lockCount字段,用于记录需要解锁的次数。
LockData lockData = (LockData)this.threadData.get(currentThread);
在internalLock方法中,首先检查当前线程是否已经持有锁,如果是,则增加lockCount;如果不是,则尝试获取锁并创建新的LockData对象来记录锁的信息。
public void release() throws Exception {
Thread currentThread = Thread.currentThread();
LockData lockData = (LockData)this.threadData.get(currentThread);
if (lockData == null) {
throw new IllegalMonitorStateException("You do not own the lock: " + this.basePath);
} else {
int newLockCount = lockData.lockCount.decrementAndGet();
if (newLockCount <= 0) {
if (newLockCount < 0) {
throw new IllegalMonitorStateException("Lock count has gone negative for lock: " + this.basePath);
} else {
try {
this.internals.releaseLock(lockData.lockPath);
} finally {
this.threadData.remove(currentThread);
}
}
}
}
}
在release方法中,会根据lockCount的值来判断是否需要真正释放锁。只有当lockCount减为0时,才会执行真正的释放操作(删除节点)。如果lockCount大于0,则只是减少lockCount的值,而不进行实际的节点操作。
简而言之,只有当lockCount为0时,才会执行真正的节点操作。
本文讲述了作者在使用ZooKeeper实现分布式锁时遇到死锁问题,转而研究Curator中的InterProcessMutex,重点介绍了Curator如何通过可重入锁和LockData结构来避免和处理死锁,特别是lockCount字段在释放锁过程中的关键作用。
563

被折叠的 条评论
为什么被折叠?



