Basics, failure semantics on 26 vs 27, lazy collections, API across 25/26/27, preview-flag traps and a JMH read-path benchmark (jars fetched and sha1-checked, not committed). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01TF9JWFvJSNm6HVzswzZU5a
53 lines
2.0 KiB
Java
53 lines
2.0 KiB
Java
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<Config> LAZY_STATIC = LazyConstant.of(() -> new Config(7));
|
|
|
|
// 5. LazyConstant in a static field that is NOT final.
|
|
static LazyConstant<Config> lazyNonFinalStatic = LazyConstant.of(() -> new Config(7));
|
|
|
|
// 6. LazyConstant in an ordinary final instance field.
|
|
final LazyConstant<Config> 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; }
|
|
}
|