The main technique for keeping the number of runnable threads down is to have each thread
do a small amount of work and then wait for some condition using Object.wait or for some
time to elapse using Thread.sleep. Threads should not busy-wait,repeatedly checking a data
structure waiting for something to happen. Besides making the program vulnerable to the
vagaries of the scheduler,busy-waiting can greatly increase the load on the processor,
reducing the amount of useful work that other processes can accomplish on the same machine.
然后继续显示忙碌等待的微基准测试与正确使用信号.在书中,忙碌等待执行17次往返/秒,而等待/通知版本每秒执行23,000次往返.
但是,当我在JDK 1.6上尝试相同的基准测试时,我看到恰恰相反 – 忙等待是760K往返/秒,而等待/通知版本是53.3K往返/秒 – 也就是说,等待/通知应该是~1400时间更快,但结果慢了约13倍?
我知道繁忙的等待并不好,信号仍然更好 – 忙等待版本的cpu利用率约为50%,而等待/通知版本的停留率约为30% – 但有没有解释数字的东西?
如果它有帮助,我在Win 7 x64(核心i5)上运行JDK1.6(32位).
更新:来源如下.要运行繁忙的工作台,请将PingPongQueue的基类更改为BusyWorkQueue
import java.util.LinkedList;
import java.util.List;
abstract class SignalWorkQueue { private final List queue = new LinkedList(); private boolean stopped = false; protected SignalWorkQueue() { new WorkerThread().start(); } public final void enqueue(Object workItem) { synchronized (queue) { queue.add(workItem); queue.notify(); } } public final void stop() { synchronized (queue) { stopped = true; queue.notify(); } } protected abstract void processItem(Object workItem) throws InterruptedException; private class WorkerThread extends Thread { public void run() { while (true) { // Main loop Object workItem = null; synchronized (queue) { try { while (queue.isEmpty() && !stopped) queue.wait(); } catch (InterruptedException e) { return; } if (stopped) return; workItem = queue.remove(0); } try { processItem(workItem); // No lock held } catch (InterruptedException e) { return; } } } } } // HORRIBLE PROGRAM - uses busy-wait instead of Object.wait! abstract class BusyWorkQueue { private final List queue = new LinkedList(); private boolean stopped = false; protected BusyWorkQueue() { new WorkerThread().start(); } public final void enqueue(Object workItem) { synchronized (queue) { queue.add(workItem); } } public final void stop() { synchronized (queue) { stopped = true; } } protected abstract void processItem(Object workItem) throws InterruptedException; private class WorkerThread extends Thread { public void run() { final Object QUEUE_IS_EMPTY = new Object(); while (true) { // Main loop Object workItem = QUEUE_IS_EMPTY; synchronized (queue) { if (stopped) return; if (!queue.isEmpty()) workItem = queue.remove(0); } if (workItem != QUEUE_IS_EMPTY) { try { processItem(workItem); } catch (InterruptedException e) { return; } } } } } } class PingPongQueue extends SignalWorkQueue { volatile int count = 0; protected void processItem(final Object sender) { count++; SignalWorkQueue recipient = (SignalWorkQueue) sender; recipient.enqueue(this); } } public class WaitQueuePerf { public static void main(String[] args) { PingPongQueue q1 = new PingPongQueue(); PingPongQueue q2 = new PingPongQueue(); q1.enqueue(q2); // Kick-start the system // Give the system 10 seconds to warm up try { Thread.sleep(10000); } catch (InterruptedException e) { } // Measure the number of round trips in 10 seconds int count = q1.count; try { Thread.sleep(10000); } catch (InterruptedException e) { } System.out.println(q1.count - count); q1.stop(); q2.stop(); } }