java - 为什么 Semaphore 可以工作,而 ReentrantLock 不行?
问题描述
我正在尝试 Leetcode 的一个简单的并发问题。我在大学里非常简短地研究过这个主题,但没有使用 Java API。似乎我不能使用 a ReentrantLock
(或据我所知的任何其他Lock
方法)来解决问题而不会遇到IllegalMonitorStateException
. 然而 a Semaphore
(这似乎有点矫枉过正,因为我只需要使用二进制值)似乎工作正常。为什么是这样?
Binary Semaphore vs ReentrantLock表明(如果我理解正确的话)二进制锁只能由获取它的线程释放,这可能是我的问题的根源,因为我在下面代码的构造函数中获取它们。有没有其他自然的方法可以使用锁/不使用信号量来解决这个问题?
带有Lock
s 的代码会引发IllegalMonitorStateException
:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Foo {
private Lock printedFirst;
private Lock printedSecond;
public Foo() {
this.printedFirst = new ReentrantLock();
this.printedSecond = new ReentrantLock();
printedFirst.lock();
printedSecond.lock();
}
public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
printedFirst.unlock();
}
public void second(Runnable printSecond) throws InterruptedException {
printedFirst.lock();
try {
printSecond.run();
} finally {
printedSecond.unlock();
}
}
public void third(Runnable printThird) throws InterruptedException {
printedSecond.lock();
try {
printThird.run();
} finally {}
}
}
带有 s 的代码Semaphore
按预期工作:
import java.util.concurrent.Semaphore;
class Foo {
private Semaphore printedFirst;
private Semaphore printedSecond;
public Foo() {
this.printedFirst = new Semaphore(0);
this.printedSecond = new Semaphore(0);
}
public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
printedFirst.release();
}
public void second(Runnable printSecond) throws InterruptedException {
printedFirst.acquire();
try {
printSecond.run();
} finally {
printedSecond.release();
}
}
public void third(Runnable printThird) throws InterruptedException {
printedSecond.acquire();
try {
printThird.run();
} finally {}
}
}
解决方案
正如您所发现的,信号量很容易实现和推理——获取锁、执行操作、释放锁。ReentrantLocks 是不同的,旨在用于您发布的示例中不存在的更复杂的目的。是的,ReentrantLocks 由单个线程拥有,并且只能由该线程释放。
如果您的目标是生成供两个线程使用的受保护代码,那么使用 Semaphore 将比 ReentrantLock 更简单且不易出错。但是,如果您的目标是了解 ReentrantLocks 的工作原理(或者如果您的用例以某种方式更适合 ReentrantLocks,而不是从上面的示例中清楚地看到),我鼓励您阅读 Javadoc - https://docs.oracle.com/ javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html - 它包含有关如何使用它们以及它们的行为方式的有用信息。