我有一个对象:
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;
}
}
我想停止线程"一个"直到线程"两个"更改变量"已处理"为真。经过"处理后#34;设置为true我想唤醒线程"一个"并继续做一些事情。
我知道我们可以使用wait和notify方法来组织它,但由于中断而非常危险。
如果我只使用等待和通知方法,那么当我等待无穷大时可能会出现这种情况
如果我们的等待方法因某种原因而中断,我们会检查"进程"变量仍然是假的,之后我们可以像这样再次使用等待:
while(true){
if(!resource.isProcessed()){
resource.getLock().wait();
}
else{
break;
}
}
使用这样的代码是危险的,因为在我们检查了"!resource.isProcessed()"在我们使用" resource.getLock()。wait()"之前另一个过程可以设置"过程"为true并调用" resource.getLock()。notify()" (这不会产生任何影响,因为我们还没有调用" wait()")。
如何安全地等待某些情况?如何安全地通知/解锁某些条件?
答案 0 :(得分:0)
您可以使用CountDownLatch使一个线程等待,直到另一个线程执行的操作完成。
假设T1和T2是您的主题,并且他们共享CountDownLatch
,并使用1
计数器进行初始化。 T1将在锁存器上首先await()
,而T2应执行其操作,然后在锁存器上调用countDown()
以使T1继续运行。
当然,T1中的await()
仍可能被中断,因此您可能希望在循环中调用它。
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();
}
}
答案 1 :(得分:0)
正如Peter Lawrey在评论中回答的那样,java中有Condition。 (谢谢你的指点)
以下是文档中提供的示例的复制过程:
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();
}
}
}