java - 为什么书中的 ReentrantLock 算法不起作用?
问题描述
今天我读了Nir Shavit, Maurice Herlihy, The Art of Multiprocessor Programming并且遇到了一件(对我个人而言)非常难以理解的事情。
所以,我在 java 中找到了ReentrantLock的实现(对我来说是第 188 页,第 8 章):
class SimpleReentrantLock implements Lock {
Lock lock;
Condition condition;
long owner, holdCount;
SimpleReentrantLock() {
lock = new SimpleLock();
condition = lock.newCondition();
owner = 0;
holdCount = 0;
}
@Override
public void lock() {
long me = Thread.currentThread().getId();
lock.lock();
if (owner == me) {
holdCount++;
return;
}
while (holdCount != 0) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
owner = me;
holdCount = 1L;
}
@Override
public void unlock() {
lock.lock();
try {
if (holdCount == 0 || owner != Thread.currentThread().getId()) {
throw new IllegalMonitorStateException();
}
holdCount--;
if (holdCount == 0) {
condition.signal();
}
} finally {
lock.unlock();
}
}
// Other methods for Lock interface...
}
我分析了这段代码,但仍然没有完全理解它。
所以,我可以这样使用ReentrantLock
from java.util.concurrent.locks
:
lock.lock();
lock.lock();
// Some code here...
lock.unlock();
lock.unlock();
没关系,因为它是 ReentrantLock,我可以多次获取临界区。
例如,您可以从本书中找到自旋锁实现:
class TASLock implements Lock {
private AtomicBoolean state = new AtomicBoolean(false);
@Override
public void lock() {
while(state.getAndSet(true));
}
@Override
public void unlock() {
state.set(false);
}
// Other Lock methods...
}
此实现按预期工作。
SimpleReentrantLock
因此,您可以从下一件事中注意到:
lock = new SimpleLock();
正如作者告诉我们的:
我们将内部锁字段初始化为(虚构的)SimpleLock 类的对象,该类可能是不可重入的
但实际上,我已经实现了不可重入锁(TASLock
),所以我将进行下一个内联:
lock = new TTASLock();
最后,当我尝试执行下一个代码时,我会陷入僵局:
new Thread(() -> {
lock.lock();
lock.lock();
System.out.println("No deadlock found.");
lock.unlock();
lock.unlock();
}).start();
它看起来很清楚,因为在lock
方法中我们有这样的代码:
lock.lock();
我们实际上试图在没有任何先决条件的情况下在同一个锁对象上两次获取临界区。
书中是否指出了错误的算法?还是我没明白什么?
解决方案
lock() 方法中缺少 lock.unlock()。该算法是正确的,这是一个简单的疏忽。
如书中所述:
因为这两个字段是原子操作的,所以我们需要一个内部短期锁。
要回答评论中的问题,这里是 lock() 的更正版本:
public void lock() {
long me = Thread.currentThread().getId();
lock.lock();
try{
if (owner == me) {
holdCount++;
return;
}
while (holdCount != 0) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
owner = me;
holdCount = 1L;
} finally {
lock.unlock(); // this call is missing
}
}
推荐阅读
- python - 如何格式化numpy数组?
- django - django 一次清理多个字段
- android - 无法启动守护进程。错误仍然存在
- microsoft-teams - Microsoft Teams Webhook 为自适应卡生成 400
- python-3.x - 我如何对阿拉伯语列表进行排序
- python - python中两个图像的差异没有得到正确的减法结果
- python - Python元组:比较和合并没有for循环
- cassandra - Cassandra实时数据查询错误
- fpga - windows 程序如何将输入和输出传输到 FPGA
- python-3.x - Python Selenium“无法连接到服务%s”%self.path在linux服务器中