AtomicLong的incrementAndGet方法是如何在内部工作的



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

@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方法将以原子方式增加当前值1。这意味着每个线程都有可能等待其他线程增加该值。我说的对吗?意味着它会被阻塞?

这也会影响我衡量任何方法性能的方式吗?这意味着它也会给测量增加一些额外的时间?

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

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

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方法,如果它是添加额外的时间到我的性能测量,那么它可能是我没有得到准确的结果?

更新:-

这是下面的方法,当我在eclipseincrementAndGet上执行F3时得到的。

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

/**
 * 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,与SUN JVM相比,我正在运行IBM JVM。因为我在一家公司工作,我不能改变这个特殊的事情。

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

谢谢你的帮助

别担心。除非你是在写一个像外汇平台之类的东西,否则这个很小很小的延迟并不重要。为了给你一个概念,我们将以纳秒的顺序进行讨论,而在应用程序代码中,我们通常以毫秒为单位。此外,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;
    }
}

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

但是,您可以复制AtomicLong的Sun JVM实现以使用非阻塞实现,因为IBM VM也应该具有CAS操作。只有当您期望中度到高度的争用(大量线程)时,这才有可能带来显著的改进。如果没有,我认为锁解决方案的执行效果与当前改进的锁实现(如果我没记错,可以从JDK6中获得)几乎相同。

实际上,如果您有非常高的争用,锁可以比非阻塞解决方案执行得更好。因此,理想情况下,您必须使用两个实现并比较结果……这就是为什么我认为你不应该麻烦的原因,因为在那段时间里,你可以在其他地方做一些性能改进,这会给你带来超过100万倍的改进,你可以通过这里解决问题。

最新更新