Joshua Bloch的“Effective Java”,项目51不是依赖于线程调度器,也不是在可运行状态下不必要地保持线程。引用文字:Java并发JDK 1.6:繁忙等待比信令更好吗?有效的Java#51
保持运行的线程数量下降的主要技术是让每个线程 做的工作少量,然后等待使用的Object.wait或一段时间 使用流逝一些条件了Thread.sleep。线程不应该忙于等待,反复检查数据结构等待发生。除了使程序容易受到调度程序变幻莫测的影响外,繁忙等待可以大大增加处理器的负载,减少其他进程在同一台机器上可以完成的有用工作量。
然后继续显示一个忙碌的等待与正确使用信号的微基准。在这本书中,忙碌的等待每秒钟进行17次,而等待/通知版本则每秒进行23,000次往返。但是,当我在JDK 1.6上尝试相同的基准测试时,我看到的恰恰相反 - 忙等待时间为760K往返/秒,而等待/通知版本则为53.3K往返/秒 - 即等待/通知应该已经快了1400倍,但实际上慢了13倍?
我知道忙碌的等待并不好,信号仍然更好 - 在繁忙的等待版本上cpu利用率为〜50%,而在wait/notify版本上cpu利用率保持在〜30% - 但有没有解释号码?
如果有帮助,我在Win 7 x64(core i5)上运行JDK1.6(32位)。
UPDATE:Source below。要运行繁忙的工作台,将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();
}
}
我认为就是这样。刚试过了。在将物品放入另一个队列之前先引入1ms睡眠,两次运行几乎完全相同 - 大约400次往返/秒。正如所料,繁忙的等待消耗了3倍以上的CPU。谢谢! – Raghu 2010-07-22 18:39:22