package bench; import org.openjdk.jmh.annotations.*; import java.util.concurrent.TimeUnit; /** * Cost of READING an already-initialised lazily-built value, six ways. Every variant returns k + x, where x is an * ordinary mutable field, so the JIT cannot fold the whole method away, but can fold a constant k. */ @State(Scope.Benchmark) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public class AccessBench { record Config(int k) {} // 1. Eager static final: the reference point, always initialised, always foldable. static final Config EAGER = new Config(7); // 2. Holder idiom. static class Holder { static final Config VALUE = new Config(7); } // 3. Double-checked locking with a volatile field. static volatile Config dclField; static Config dcl() { Config local = dclField; if (local == null) { synchronized (AccessBench.class) { local = dclField; if (local == null) dclField = local = new Config(7); } } return local; } // 4. LazyConstant in a static final field: the case the JEP is designed for. static final LazyConstant LAZY_STATIC = LazyConstant.of(() -> new Config(7)); // 5. LazyConstant in a static field that is NOT final. static LazyConstant lazyNonFinalStatic = LazyConstant.of(() -> new Config(7)); // 6. LazyConstant in an ordinary final instance field. final LazyConstant lazyInstance = LazyConstant.of(() -> new Config(7)); int x = 3; @Benchmark public int eagerStaticFinal() { return EAGER.k() + x; } @Benchmark public int holderIdiom() { return Holder.VALUE.k() + x; } @Benchmark public int doubleCheckedLocking() { return dcl().k() + x; } @Benchmark public int lazyConstantStaticFinal() { return LAZY_STATIC.get().k() + x; } @Benchmark public int lazyConstantNonFinalStatic() { return lazyNonFinalStatic.get().k() + x; } @Benchmark public int lazyConstantInstanceField() { return lazyInstance.get().k() + x; } }