如何使用 Java 中的锁来等待特殊条件?
How to use a lock in Java to wait for the special condition?
我有一个对象:
public class Resource {
private Lock lock = new ReentrantLock();
private boolean processed = false;
public Lock getLock() {
return lock;
}
public boolean isProcessed() {
return processed;
}
public void setProcessed(boolean processed) {
this.processed = processed;
}
}
我想停止线程 "one",直到线程 "two" 将变量 "processed" 更改为 true。 "processed" 设置为 true 后,我想唤醒线程 "one" 并继续做一些事情。
我知道可以用wait和notify的方法来组织,但是很危险,因为会中断。
如果我只使用等待和通知方法,可能会出现无限等待的情况。
如果我们的 wait 方法由于某种原因被中断,我们检查 "process" 变量是否仍然为 false 之后我们可以像这里一样再次使用 wait:
while(true){
if(!resource.isProcessed()){
resource.getLock().wait();
}
else{
break;
}
}
使用这样的代码是危险的,因为在我们检查了“!resource.isProcessed()”之后,在我们使用 "resource.getLock().wait()" 之前,另一个进程可以将 "process" 设置为 true 并且调用 "resource.getLock().notify()"(不会生效,因为我们还没有调用 "wait()")。
如何安全地等待某个条件?如何notify/unlock安全一些条件?
您可以使用 CountDownLatch 让一个线程等待,直到另一个线程执行的操作完成。
让我们假设 T1 和 T2 是您的线程,它们共享一个 CountDownLatch
,并用 1
的计数器初始化。 T1 将首先 await()
锁存器,而 T2 应该执行其操作,然后在锁存器上调用 countDown()
让 T1 继续。
当然await()
在T1中还是可以打断的,所以可能要循环调用。
class T1 implements Runnable {
private final CountDownLatch latch;
T1(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
awaitUninterruptibly(latch);
doWork();
}
private void awaitUninterruptibly(CountDownLatch latch) {
boolean interrupted = false;
try {
while (true) {
try {
latch.await();
return;
} catch (InterruptedException e) {
interrupted = true;
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
}
class T2 implements Runnable {
private final CountDownLatch latch;
T1(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
doWork();
latch.countDown();
}
}
作为 Peter Lawrey answered in comments there are Condition 在 java 中可用。 (谢谢指点)
这是文档中提供的示例的副本:
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
我有一个对象:
public class Resource {
private Lock lock = new ReentrantLock();
private boolean processed = false;
public Lock getLock() {
return lock;
}
public boolean isProcessed() {
return processed;
}
public void setProcessed(boolean processed) {
this.processed = processed;
}
}
我想停止线程 "one",直到线程 "two" 将变量 "processed" 更改为 true。 "processed" 设置为 true 后,我想唤醒线程 "one" 并继续做一些事情。
我知道可以用wait和notify的方法来组织,但是很危险,因为会中断。
如果我只使用等待和通知方法,可能会出现无限等待的情况。
如果我们的 wait 方法由于某种原因被中断,我们检查 "process" 变量是否仍然为 false 之后我们可以像这里一样再次使用 wait:
while(true){
if(!resource.isProcessed()){
resource.getLock().wait();
}
else{
break;
}
}
使用这样的代码是危险的,因为在我们检查了“!resource.isProcessed()”之后,在我们使用 "resource.getLock().wait()" 之前,另一个进程可以将 "process" 设置为 true 并且调用 "resource.getLock().notify()"(不会生效,因为我们还没有调用 "wait()")。
如何安全地等待某个条件?如何notify/unlock安全一些条件?
您可以使用 CountDownLatch 让一个线程等待,直到另一个线程执行的操作完成。
让我们假设 T1 和 T2 是您的线程,它们共享一个 CountDownLatch
,并用 1
的计数器初始化。 T1 将首先 await()
锁存器,而 T2 应该执行其操作,然后在锁存器上调用 countDown()
让 T1 继续。
当然await()
在T1中还是可以打断的,所以可能要循环调用。
class T1 implements Runnable {
private final CountDownLatch latch;
T1(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
awaitUninterruptibly(latch);
doWork();
}
private void awaitUninterruptibly(CountDownLatch latch) {
boolean interrupted = false;
try {
while (true) {
try {
latch.await();
return;
} catch (InterruptedException e) {
interrupted = true;
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
}
class T2 implements Runnable {
private final CountDownLatch latch;
T1(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
doWork();
latch.countDown();
}
}
作为 Peter Lawrey answered in comments there are Condition 在 java 中可用。 (谢谢指点)
这是文档中提供的示例的副本:
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}