2010-10-26 40 views
1

我想了解多线程环境中的性能。为此我写了一个小测试,在我的机器上运行(四核英特尔,Windows XP,Sun JDK 1.6.0_20),结果令人惊讶。多线程Java应用程序的性能

测试基本上是使用任一​​关键字或一个显式锁定同步的线程安全计数器。下面是代码:

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"); 
    } 
    } 
} 

我提出以下意见:

  1. java SynchronizedPerformance 1 synchronized工作得很好,并采取每步大约15纳秒。
  2. java SynchronizedPerformance 2 synchronized干扰很多,每步大约需要150 ns。
  3. 当我开始的java SynchronizedPerformance 2 synchronized两个独立的过程它们中的每需要每步大约100纳秒。也就是说,第二次启动过程会使第一个(和第二个)更快。

我不明白第三观察。这种现象存在什么合理的解释?

+2

你需要重复运行的微基准测试,否则自然变异会在测量中压倒任何实际信号。运行数十次或数百次。 – 2010-10-26 22:09:53

+0

我已经做了。效果是一样的。特别是在场景3中,当我只启动一个进程时,应用程序很慢,而且每当我启动第二个进程时,应用程序都会更快。当我稍后停止第二个过程时,第一个过程再次变慢。 – 2010-10-27 06:02:37

回答

1

您正在运行到的情况下的表现完全依赖于如何调度工作。在#3中,当系统中的任何其他进程需要一段时间(甚至一点点)时,它将挂起4个线程中的一个。如果该线程在暂停时没有保持锁定状态,那么它的“对”现在可以无争议地运行,并且会取得很多进展(与竞争情况相比,以20倍的速度运行)。

当然,如果换出时,它持有的锁,其“对”就不能取得进展。所以你有两个相互竞争的因素,整体运行时间取决于线程持有锁的时间分数以及你在每种情况下获得的惩罚/奖励。你的奖金非常丰富,所以我希望你看到一些整体加速。

+0

您是否暗示Java中的锁定是跨不同的JVM进程共享的?因为这是不正确的。 – 2010-10-27 00:02:21

+0

对不起,我相信我在几个应该使用“线程”的地方使用了“进程”。我会编辑。 – 2010-10-27 05:16:44

1

最可能的情况是存在某些固定开销,无论存在多少个线程 - 例如垃圾回收或其他资源管理。