我有这样的代码:
public class RecursiveQueue {
//@Inject
private QueueService queueService;
public static void main(String[] args) {
RecursiveQueue test = new RecursiveQueue();
test.enqueue(new Node("X"), true);
test.enqueue(new Node("Y"), false);
test.enqueue(new Node("Z"), false);
}
private void enqueue(final Node node, final boolean waitTillFinished) {
final AtomicLong totalDuration = new AtomicLong(0L);
final AtomicInteger counter = new AtomicInteger(0);
AfterCallback callback= new AfterCallback() {
@Override
public void onFinish(Result result) {
for(Node aNode : result.getChildren()) {
counter.incrementAndGet();
queueService.requestProcess(aNode, this);
}
totalDuration.addAndGet(result.getDuration());
if(counter.decrementAndGet() <= 0) { //last one
System.out.println("Processing of " + node.toString() + " has finished in " + totalDuration.get() + " ms");
if(waitTillFinished) {
counter.notify();
}
}
}
};
counter.incrementAndGet();
queueService.requestProcess(node, callback);
if(waitTillFinished) {
try {
counter.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
想象一下,有一个queueService
使用阻塞队列和很少的消费者线程来处理节点=调用DAO来获取节点的子节点(它是一棵树)。
所以requestProcess
方法只是将节点排队并且不阻塞。
是否有更好/安全的方法可以避免在此示例中使用wait / notify? 根据一些调查结果,我可以使用Phaser(但我在java 6上工作)或条件(但我没有使用锁)。
答案 0 :(得分:3)
您的示例中没有synchronized
任何内容。除非o.wait()
阻止,否则您无法致电o.notify()
或synchronized(o) {...}
。
您对wait()
的电话不在循环中。这可能不会在您的JVM中发生,但语言规范允许wait()
过早返回(这被称为虚假唤醒)更一般地说,总是优秀的做法使用循环是因为它是一种熟悉的设计模式。 while
语句的费用不会超过if
,而 应该拥有它,因为虚假唤醒的可能性,并且你绝对必须< / em>让它处于多消费者的情况下,所以你不妨总是这样写。
由于您必须使用synchronized
块才能使用wait()
和notify()
,因此可能没有理由使用Atomic
任何内容。
这个&#34;递归&#34;事情看起来非常复杂,回调会向队列中添加更多项目。这有多深?
答案 1 :(得分:0)
我认为您正在寻找CountDownLatch。
答案 2 :(得分:0)
你实际上使用了锁,或者让我们这样说,如果你试图像James指出的那样尝试使用wait / notify,你应该使用它们。由于您无法使用Java 1.6和ForkJoin或Phaser,因此选择正确实现wait / notify或使用带有显式锁定的Condition。这将取决于您的个人喜好。
另一种方法是尝试重构您的算法,以便您首先了解执行所需的整个步骤集。但这并不总是可能的。