2010-10-26 43 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

最可能的情況是存在某些固定開銷,無論存在多少個線程 - 例如垃圾回收或其他資源管理。