多线程Java应用程序中的性能 [英] Performance in multithreaded Java application

查看:100
本文介绍了多线程Java应用程序中的性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解多线程环境中的性能.为此,我编写了一个在机器(四核Intel,Windows XP,Sun JDK 1.6.0_20)上运行的小型测试,结果令人惊讶.

I want to understand performance in multithreaded environments. For that I have written a small test that I ran on my machine (quad-core Intel, Windows XP, Sun JDK 1.6.0_20), with surprising results.

该测试基本上是一个线程安全计数器,可以使用synchronized关键字或显式锁进行同步.这是代码:

The test is basically a thread-safe counter that is synchronized using either the synchronized keyword or an explicit lock. Here is the code:

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.也就是说,第二次启动该过程会使第一个(和第二个)更快.
  1. java SynchronizedPerformance 1 synchronized works pretty well, and takes about 15 ns per step.
  2. java SynchronizedPerformance 2 synchronized interferes a lot and takes about 150 ns per step.
  3. When I start two independent processes of java SynchronizedPerformance 2 synchronized each of them takes about 100 ns per step. That is, starting the process a second time makes the first one (and the second) faster.

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

I don't understand the third observation. What plausible explanations exist for this phenomenon?

推荐答案

您正在遇到一种情况,即性能完全取决于调度程序的运行方式.在#3中,当系统中的任何其他进程需要一些时间(甚至一点点)时,它将挂起您的4个线程之一.如果该线程在挂起时碰巧没有保持锁定,那么它的对"现在可以毫无争议地运行,并且可以取得很大的进步(与有争议的情况相比,运行速度是20倍).

You are running into a situation where performance is entirely dependent on how the scheduler operates. In #3, when any other process in the system wants some time (even a little bit), it will suspend one of your 4 threads. If that thread happens to not hold the lock at when it is suspended, its "pair" can now run uncontested, and will make lots of progress (runs at 20x speed compared to the contested situation).

当然,如果在握住锁时将其换出,则其对"将没有任何进展.因此,您有两个相互竞争的因素,整个运行时间取决于线程持有锁的时间比例以及每种情况下的损失/奖金.您的奖金是可观的,所以我希望像您看到的那样总体上有所提速.

Of course, if it is swapped out when it does hold the lock, its "pair" will make no progress. So you have two competing factors, and the overall runtime depends on the fraction of time the lock is held by a thread and the penalty/bonus you get for each situation. Your bonus is substantial so I would expect some overall speedup like you saw.

这篇关于多线程Java应用程序中的性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆