[英]What does it mean to return a value after calling wait()?
在下面的代码中,我有一个关于调用wait()后会发生什么的问题。 在我的代码中,我在调用wait()
后返回一个值,这实际上是做什么的? 我认为,调用wait()
挂起当前线程,但会发生什么变化值i
传递给addWorkItem(Integer i)
如果wait()
调用时没有返回false? 您可以在生产者线程中看到,如果无法将其添加到deque中,则会将i
添加到重试缓冲区。 如果我不等待后返回false,确实值i
只是迷路了,或者是它仍然存在,一旦线程被唤醒?
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
public class ConsumerProducer2 {
private static int QUEUE_SIZE = 10;
private Deque<Integer> queue = new ArrayDeque<Integer>(QUEUE_SIZE);
public synchronized boolean addWorkItem(Integer i) {
while (queue.size() >= QUEUE_SIZE) {
try {
wait();
return false; // WHAT HAPPENS HERE?
} catch (InterruptedException ex) {}
}
queue.addLast(i);
notify();
return true;
}
public synchronized Integer getWork() {
while (queue.size() == 0) {
try {
wait();
return null; // WHAT HAPPENS HERE?
} catch (InterruptedException ex) {
}
}
Integer i = queue.removeFirst();
notify();
return i;
}
public static void main(String[] args) {
new ConsumerProducer2().go();
}
public void go() {
ConsumerThread ct = new ConsumerThread();
ct.start();
ConsumerThread ct2 = new ConsumerThread();
ct2.start();
ProducerThread pt = new ProducerThread();
pt.start();
}
class ConsumerThread extends Thread {
public void run() {
while(true) {
Integer work = getWork();
if (work == null) {
} else {
System.out.println("Thread: " + this.getId() + " received work: " + work);
}
}
}
}
class ProducerThread extends Thread {
private List<Integer> retryList = new ArrayList<Integer>();
public void run() {
while(true) {
Integer currWork;
if (retryList.size() == 0) {
currWork = (int) (Math.random() * 100);
} else {
currWork = retryList.remove(0);
System.out.println("Thread: " + this.getId() + " retrying old work: " + currWork);
}
if (!addWorkItem(currWork)) {
System.out.println("Thread: " + this.getId() + " could not add work (because buffer is probably full): " + currWork);
retryList.add(currWork);
} else {
System.out.println("Thread: " + this.getId() + " added work to queue: " + currWork);
}
}
}
}
}
让生产者维护重试缓冲区确实使i值不会丢失,但这仍然不是编写方法的好方法。
从while循环内部返回没有意义。 你检查队列的大小,如果它已经达到最大值,你就等到你得到队列大小改变的通知,然后莫名其妙地返回false(??)。 等待并没有真正完成任何事情。
addWorkItem中的等待点是延迟线程,直到队列有新值的空间。 你应该在循环中等待,当你退出等待时,你的线程重新获取锁并重新检查条件(队列大小>最大),看它是否可以添加项目。
一旦线程退出while循环,它就会持有锁,它确保新项目的队列中有足够的空间(因为没有其他线程可以做任何事情来改变队列的大小,而这个线程有锁定),它可以继续并将值添加到队列中。
您正在以非生产性的方式捕获InterruptedException,因为您捕获它,不必费心恢复中断标志,并返回到while循环的顶部。 你应该使用中断来退出等待并退出方法。 让InterruptedException抛出这里会更有意义; 运行该方法的线程应该比这个对象更好地了解如何处理中断。
您不应该假设等待仅在通知线程时返回,它可以在没有通知的情况下返回。 这是在循环中调用wait的原因之一。
返工版本:
public synchronized boolean addWorkItem(Integer i) throws InterruptedException {
while (queue.size() >= QUEUE_SIZE) {
wait();
}
queue.addLast(i);
notify();
return true;
}
如果你想借口从这里返回false,那么如果队列在一段时间内没有为新条目腾出空间,那么你可以使方法返回false(在很多现实情况下,超时可能是一件好事):
public synchronized boolean addWorkItem(Integer i) throws InterruptedException {
final long maxWaitTime = 60L * 1000;
long totalWaitTime = 0;
while (queue.size() >= QUEUE_SIZE && totalWaitTime <= maxWaitTime) {
long waitStartTime = System.currentTimeMillis();
wait(maxWaitTime);
totalWaitTime += (System.currentTimeMillis() - waitStartTime);
}
if (queue.size() >= QUEUE_SIZE) {
return false;
}
queue.addLast(i);
notify();
return true;
}
这仍然会使用重试缓冲区(它上面的第一个版本根本不会执行),但可能不会像现在这样多。
另一件事:你有生产者和消费者线程同时访问它,并且两种情况都会调用notify。 由于通知仅唤醒一个线程,因此线程可能会获得与其无关的通知(因此通知的线程会唤醒,检查其状况并发现它仍然是假的,然后等待更多,而另一个线程,通知实际上很重要,从来没有发现它)。 你可以用不同的方法解决问题
分配单独的锁,一个用于生产者,一个用于消费者,
减少传递给wait方法的超时,这样你就不会依赖于获得通知,或者
你可以使用notifyAll(性能较差但快速修复)。
看看这个 。
简短的故事 :一个等待的线程可以被另一个呼叫通知唤醒。 所以在你的情况下,addWorkItem将在另一个线程调用notify()
之后调用wait()
的线程中返回false。
另外看看你的逻辑我认为你在队列为空时试图阻止消费者,并在有工作要做的时候唤醒它。 并且您希望生产者在队列为空之前不要提供新的工作。 如果是这种情况,那么在等待之后调用return将关闭你的消费者/生产者,而不是让他们尽可能地完成他们的工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.