6

我在我的多线程代码中使用incrementAndGet方法AtomicLong来测量我们的一些客户端代码的性能。

@Override
public void run() {


   long start = System.nanoTime();

   attributes = client.getAttributes(columnsList);

   long end = System.nanoTime() - start;

   final AtomicLong before = select.putIfAbsent(end / 1000000L, new AtomicLong(1L));
        if (before != null) {
            before.incrementAndGet();
        }
}

在上面的代码中,我试图测量多少时间-

client.getAttributes(columnsList);

正在服用。

据我所知,incrementAndGet方法将以原子方式将当前值增加一。这意味着每个线程可能会等待其他线程增加该值。我对吗?意思是会被屏蔽?

这是否会影响我测量任何方法的性能的方式?这意味着它还会为该测量增加一些额外的时间吗?

为什么我问这个是因为我正在尝试对我们的大多数客户端代码和服务器端代码进行基准测试,如果我需要测量每种方法所花费的时间,那么我就是这样做 -

无论我想测量什么代码,我通常将下面的行放在该方法的正上方

long start = System.nanoTime();

这两行采用相同的方法但不同ConcurrentHashMap

long end = System.nanoTime() - start;

final AtomicLong before = select.putIfAbsent(end / 1000000L, new AtomicLong(1L));
    if (before != null) {
        before.incrementAndGet();
    }

因此,如果我正在使用incrementAndGet方法并且如果它为我的性能测量增加了额外的时间,那么我可能没有得到准确的结果?

更新:-

这是下面的方法,我F3incrementAndGetin上做的时候得到的eclipse

所以这里有一个同步块。这意味着每个线程都会在这里等待其他线程。这是一个阻塞呼叫。

/**
 * Atomically increments by one the current value.
 *
 * @return the updated value
 */
public final synchronized long incrementAndGet() {                          //IBM-perf_AtomicLong
   ++value;                                                                 //IBM-perf_AtomicLong
   return value;                                                            //IBM-perf_AtomicLong
}

啊。我刚刚检查了我的 JVM,IBM JVMSUN JVM. 因为我在一家公司工作,我无法改变这个特殊的事情。

那么有什么方法可以避免这种基于锁的解决方案来衡量任何方法的性能/基准?请记住,我正在运行 IBM JVM。

谢谢您的帮助。

4

1 回答 1

8

别担心。除非您正在编写诸如外汇平台之类的东西,否则微小的延迟将无关紧要。为了给你一个想法,我们会以纳秒的数量级说话,而在应用程序代码中,我们通常以毫秒为单位说话。此外,JVM 的锁得到了显着改善。如果争用较少(这是常态),基于锁的解决方案和非阻塞解决方案之间的性能差异将很小。

令人惊讶的是,IBM JVM 为 AtomicLong 使用了锁。我认为所有主要实现都使用非阻塞 CAS。这是使用 CAS 的常见实现:

/**
 * Atomically increments by one the current value.
 *
 * @return the updated value
 */
public final long incrementAndGet() {
    for (;;) {
        long current = get();
        long next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

对后续评论的回应:
作为一个非常粗略的经验法则,如果您当前的端到端响应时间(或响应时间要求)超过 30 毫秒,我真的不会担心这一点,因为无论花费多少时间增加 long 都会在纳秒范围内。我几乎可以肯定,您会找到其他可以优化的地方,从而为您带来更多改进(例如毫秒)。

但是,您可以只复制 AtomicLong 的 Sun JVM 实现以使用非阻塞实现来代替,因为 IBM VM 也应该具有 CAS 操作。如果您期望中度到高度争用(大量线程),这可能会导致显着改进。如果你不这样做,我认为锁定解决方案的性能几乎与当前的改进锁定实现相同(如果我记得的话,可以从 JDK6 获得)。

事实上,如果您有非常高的争用,锁可以比非阻塞解决方案执行得更好。因此,理想情况下,您必须使用两个实现并比较结果...这就是为什么我认为您不应该打扰的原因,因为在那个时候,您可以在其他地方进行一些性能改进,从而使您的文学性超过 1 mil 倍于您可以通过解决此处获得的改进。

于 2013-04-14T00:29:41.413 回答