代码之家  ›  专栏  ›  技术社区  ›  Roland Illig

多线程Java应用程序的性能

  •  2
  • Roland Illig  · 技术社区  · 14 年前

    我想了解多线程环境中的性能。为此,我编写了一个在我的计算机上运行的小测试(四核Intel、Windows XP、Sun JDK 1.6.0 U 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");
        }
      }
    }
    

    我做了以下观察:

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

    我不明白第三个观察结果。对于这种现象,有什么合理的解释?

    2 回复  |  直到 14 年前
        1
  •  1
  •   Keith Randall    14 年前

    您正遇到这样一种情况:性能完全取决于调度程序的操作方式。在3中,当系统中的任何其他进程需要一段时间(甚至一点点)时,它将挂起4个线程中的一个。如果该线程在挂起时没有保持锁,那么它的“对”现在可以无条件运行,并将取得很大的进展(与有争议的情况相比,以20倍的速度运行)。

    当然,如果它在持有锁时被换出,那么它的“对”将不会有任何进展。所以您有两个相互竞争的因素,并且整个运行时取决于线程持有锁的时间比例和您在每种情况下得到的惩罚/奖励。你的奖金很可观,所以我希望能像你看到的那样全面加速。

        2
  •  1
  •   Puppy    14 年前

    最有可能的情况是,无论存在多少线程,都存在一定的固定开销,例如垃圾收集或其他资源管理。