【发布时间】:2011-05-01 00:20:27
【问题描述】:
我想了解多线程环境中的性能。为此,我编写了一个在我的机器(四核 Intel、Windows XP、Sun JDK 1.6.0_20)上运行的小测试,结果令人惊讶。
测试基本上是使用synchronized 关键字或显式锁同步的线程安全计数器。代码如下:
import java.util.concurrent.locks.ReentrantLock;
public class SynchronizedPerformance {
static class Counter {
private static final int MAX = 1 << 24;
int count;
long lastLog = 0;
private final ReentrantLock lock = new ReentrantLock();
private int incrementAndGet() {
count++;
if (count == MAX) {
long now = System.nanoTime();
if (lastLog != 0) {
long elapsedTime = now - lastLog;
System.out.printf("counting took %.2f ns\n", Double.valueOf((double)elapsedTime / MAX));
}
lastLog = now;
count = 0;
}
return count;
}
synchronized int synchronizedIncrementAndGet() {
return incrementAndGet();
}
int lockedIncrementAndGet() {
lock.lock();
try {
return incrementAndGet();
} finally {
lock.unlock();
}
}
}
static class SynchronizedCounterAccessor implements Runnable {
private final Counter counter;
public SynchronizedCounterAccessor(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
while (true)
counter.synchronizedIncrementAndGet();
}
}
static class LockedCounterAccessor implements Runnable {
private final Counter counter;
public LockedCounterAccessor(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
while (true)
counter.lockedIncrementAndGet();
}
}
public static void main(String[] args) {
Counter counter = new Counter();
final int n = Integer.parseInt(args[0]);
final String mode = args[1];
if (mode.equals("locked")) {
for (int i = 0; i < n; i++)
new Thread(new LockedCounterAccessor(counter), "ca" + i).start();
} else if (mode.equals("synchronized")) {
for (int i = 0; i < n; i++)
new Thread(new SynchronizedCounterAccessor(counter), "ca" + i).start();
} else {
throw new IllegalArgumentException("locked|synchronized");
}
}
}
我做了以下观察:
-
java SynchronizedPerformance 1 synchronized运行良好,每步大约需要 15 ns。 -
java SynchronizedPerformance 2 synchronized干扰很大,每步大约需要 150 ns。 - 当我启动
java SynchronizedPerformance 2 synchronized的两个独立进程时,每个进程每一步大约需要 100 ns。也就是说,第二次启动该过程会使第一次(和第二次)更快。
我不明白第三个观察结果。这种现象有哪些合理的解释?
【问题讨论】:
-
您需要反复运行微基准测试,否则自然方差会压倒您测量中的任何实际信号。运行数十或数百次。
-
我已经这样做了。效果是一样的。特别是在场景 3 中,当我只启动一个进程时应用程序很慢,而当我启动第二个进程时它会更快。当我稍后停止第二个进程时,第一个进程再次变慢。
标签: java multithreading performance multicore