java - 避免不必要的线程唤醒

时间:2013-04-06 16:29:51

标签: multithreading notifications throughput java1.4

我有一组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) -loop时会发生这种情况。工作行动越小/越短,就越有可能发生这种情况。

这意味着我什么都没醒来。由于我需要高吞吐量,我相信这种行为会降低性能。

你会如何解决这个问题?理论上,我需要一种机制,允许我取消挂起的线程唤醒通知。当然,这在Java中是不可能的。

我考虑为每个线程引入工作列表。这项工作分散在12个工作清单上,而不是将工作推到一个单一的清单中。但我相信这会引入其他问题。例如,一个线程可能有很多待处理的工作,而另一个线程可能没有待处理的工作。从本质上讲,我认为将工作分配给特定线程提前的解决方案可能会变得非常复杂并且不是最佳的。

谢谢!

2 个答案:

答案 0 :(得分:2)

您正在做的是一个线程池。看看pre-java-5并发框架,那里的PooledExecutor类: http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html

答案 1 :(得分:0)

除了我之前的回答 - 另一个解决方案。这个问题让我好奇。

在这里,我添加了一个带有volatile布尔值的检查。

它不能完全避免无用地唤醒线程的情况,但有助于避免它。实际上,我没有看到如果没有额外的限制可以完全避免这种情况,例如“我们知道100分钟之后很可能会完成工作”。

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
}