我有一组12个线程并行执行工作(Runnable)。实际上,每个线程都做以下工作:
Runnable r;
while (true) {
synchronized (work) {
while (work.isEmpty()) {
work.wait();
}
r = work.removeFirst();
}
r.execute();
}
增加的工作如下:
Runnable r = ...;
synchronized (work) {
work.add(r);
work.notify();
}
当新工作可用时,它被添加到列表中并通知锁。如果有一个线程在等待,它被唤醒,所以它可以执行这项工作。
问题就在这里。当一个线程被唤醒时,很可能会有另一个线程执行这项工作。当后一个线程完成之前的工作并重新进入while(true)循环时,就会发生这种情况。工作动作越小/越短,发生这种情况的可能性就越大。
这意味着我正在无缘无故地唤醒一个线程。由于我需要高吞吐量,我认为这种行为会降低性能。
你怎么解决这个问题?理论上,我需要一种机制,允许我取消挂起的线程唤醒通知。当然,这在Java中是不可能的。
我想为每个线程引入一个工作列表。而不是把工作推到一个单独的列表中,工作被分散到12个工作列表中。但我相信这会带来其他问题。例如,一个线程可能有很多待处理的工作,而另一个线程可能没有待处理的工作。从本质上讲,我认为提前将工作分配给特定线程的解决方案可能会变得非常复杂,并且不是最优的。
谢谢!
你正在做的是一个线程池。看看java-5之前的并发框架,pooledexexecutor类:http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
除了我之前的答案-另一个解决方案。这个问题使我很好奇。
这里,我添加了一个volatile boolean检查
它不能完全避免无用地唤醒线程的情况,但有助于避免这种情况。实际上,如果没有额外的限制,比如"我们知道在100ms之后,一个任务最有可能完成",我看不出这是如何完全避免的。
volatile boolean free = false;
while (true) {
synchronized (work) {
free = false; // new rev.2
while (work.isEmpty()) {
work.wait();
}
r = work.removeFirst();
}
r.execute();
free = true; // new
}
,
synchronized (work) {
work.add(r);
if (!free) { // new
work.notify();
} // new
free = false; // new rev.2
}