【问题标题】:Performance in multithreaded Java application多线程 Java 应用程序中的性能
【发布时间】: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");
    }
  }
}

我做了以下观察:

  1. java SynchronizedPerformance 1 synchronized 运行良好,每步大约需要 15 ns。
  2. java SynchronizedPerformance 2 synchronized 干扰很大,每步大约需要 150 ns。
  3. 当我启动java SynchronizedPerformance 2 synchronized 的两个独立进程时,每个进程每一步大约需要 100 ns。也就是说,第二次启动该过程会使第一次(和第二次)更快。

我不明白第三个观察结果。这种现象有哪些合理的解释?

【问题讨论】:

  • 您需要反复运行微基准测试,否则自然方差会压倒您测量中的任何实际信号。运行数十或数百次。
  • 我已经这样做了。效果是一样的。特别是在场景 3 中,当我只启动一个进程时应用程序很慢,而当我启动第二个进程时它会更快。当我稍后停止第二个进程时,第一个进程再次变慢。

标签: java multithreading performance multicore


【解决方案1】:

您遇到的情况是,性能完全取决于调度程序的运行方式。在 #3 中,当系统中的任何其他进程需要一些时间(甚至一点点)时,它将暂停 4 个线程之一。如果该线程在暂停时碰巧没有持有锁,那么它的“对”现在可以不受争议地运行,并且会取得很大进展(与有争议的情况相比以 20 倍的速度运行)。

当然,如果它在持有锁时被换出,它的“对”将没有任何进展。因此,您有两个相互竞争的因素,整体运行时间取决于线程持有锁的时间比例以及您在每种情况下获得的惩罚/奖励。你的奖金是可观的,所以我希望你看到的整体加速。

【讨论】:

  • 您是否建议Java 中的锁在不同的JVM 进程之间共享?因为这不是真的。
  • 对不起,我相信我在几个本应使用“线程”的地方使用了“进程”。我会编辑。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2011-10-07
    • 1970-01-01
    • 2013-05-25
    • 1970-01-01
    • 2012-05-29
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    相关资源
    最近更新 更多