【发布时间】:2010-07-22 17:24:11
【问题描述】:
Joshua Bloch 的“Effective Java”,第 51 项不是关于依赖于线程调度程序以及不让线程不必要地处于可运行状态。引用文字:
减少可运行线程数量的主要技术是让每个线程 做少量工作,然后使用 Object.wait 或等待一些条件 使用 Thread.sleep 的时间。线程不应该忙着等待,重复检查数据 等待某事发生的结构。除了使程序容易受到 调度器的变幻莫测,忙等待会大大增加处理器的负载, 减少其他进程可以在同一台机器上完成的有用工作量。
然后继续显示繁忙等待与正确使用信号的微基准。在本书中,忙等待每秒执行 17 次往返,而等待/通知版本每秒执行 23,000 次往返。
但是,当我在 JDK 1.6 上尝试相同的基准测试时,我看到的正好相反 - 繁忙等待每秒 760K 往返,而等待/通知版本每秒 53.3K 往返 - 也就是说,等待/通知应该有速度快了约 1400 倍,但结果却慢了约 13 倍?
我知道繁忙的等待并不好,并且信号仍然更好 - 繁忙等待版本的 CPU 利用率约为 50%,而等待/通知版本的 CPU 利用率保持在 ~30% - 但有什么可以解释数字?
如果有帮助,我将在 Win 7 x64(核心 i5)上运行 JDK1.6(32 位)。
更新:来源如下。要运行繁忙的工作台,请将 PingPongQueue 的基类更改为 BusyWorkQueue 导入 java.util.LinkedList; 导入 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();
}
}
【问题讨论】:
标签: java multithreading concurrency synchronization