Java模数是否缓慢?

Dic*_*ici 21 java performance modulo

ThreadLocal出于好奇,我一直在看JDK 中的实现,我发现了这个:

/**
 * Increment i modulo len.
 */
 private static int nextIndex(int i, int len) {
     return ((i + 1 < len) ? i + 1 : 0);
 }
Run Code Online (Sandbox Code Playgroud)

看起来很明显,这可以用一个简单的实现return (i + 1) % len,但我认为这些人知道他们的东西.知道为什么他们这样做了吗?

这段代码高度针对性能,使用自定义映射来保存线程局部映射,弱引用以帮助GC变得聪明等等,所以我想这是性能问题.Java模数是否缓慢?

apa*_*gin 25

% 在此示例中出于性能原因而避免使用.

div/ rem即使在CPU架构级别上操作也较慢; 不仅仅是在Java中.例如,idivHaswell上的最小指令延迟大约是10个周期,但只有1个周期add.

让我们使用JMH进行基准测试.

import org.openjdk.jmh.annotations.*;

@State(Scope.Benchmark)
public class Modulo {
    @Param("16")
    int len;

    int i;

    @Benchmark
    public int baseline() {
        return i;
    }

    @Benchmark
    public int conditional() {
        return i = (i + 1 < len) ? i + 1 : 0;
    }

    @Benchmark
    public int mask() {
        return i = (i + 1) & (len - 1);
    }

    @Benchmark
    public int mod() {
        return i = (i + 1) % len;
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

Benchmark           (len)  Mode  Cnt  Score   Error  Units
Modulo.baseline        16  avgt   10  2,951 ± 0,038  ns/op
Modulo.conditional     16  avgt   10  3,517 ± 0,051  ns/op
Modulo.mask            16  avgt   10  3,765 ± 0,016  ns/op
Modulo.mod             16  avgt   10  9,125 ± 0,023  ns/op
Run Code Online (Sandbox Code Playgroud)

如您所见,使用%比条件表达式慢约2.6倍.JIT无法在讨论的ThreadLocal代码中自动优化它,因为divisor(table.length)是可变的.