Writing a Benchmark
@Benchmark and modes.
Writing a Benchmark is a free Java Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Writing a Benchmark
A JMH benchmark is just a method annotated with @Benchmark inside a regular class. JMH's annotation processor generates the harness around it. This lesson covers the annotations that define what and how you measure.
The @Benchmark Annotation
Mark any public method with @Benchmark and JMH will repeatedly invoke it, timing each call. The method's return value should be returned (not discarded) so JMH can consume it.
A Minimal Benchmark Class
Here is the shape of a benchmark. The import is org.openjdk.jmh.annotations.*. Because JMH is not on this runner's classpath, this is illustrative only.
import org.openjdk.jmh.annotations.Benchmark;
public class StringBench {
@Benchmark
public String concat() {
return "foo" + System.nanoTime();
}
}Benchmark Modes
@BenchmarkMode chooses what is reported:
- Throughput — operations per unit time (higher is better).
- AverageTime — time per operation (lower is better).
- SampleTime — distribution of times (percentiles).
- SingleShotTime — one invocation, good for cold-start.
import org.openjdk.jmh.annotations.*;
public class Bench {
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public int work() {
return 2 + 2;
}
}Choosing Output Units
@OutputTimeUnit sets the time unit for the report so numbers are readable. For a fast operation, nanoseconds make sense; for a slow one, milliseconds.
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;
public class Bench {
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public int work() {
return 42;
}
}Returning Results
Always return the result of the work. JMH feeds returned values into a Blackhole automatically, preventing dead-code elimination. A void benchmark that computes and discards is a classic mistake.
Annotation Defaults
Annotations can sit on the method or on the whole class. Class-level annotations apply to every @Benchmark in that class, which keeps configuration DRY when you have several related benchmarks.
Forking
@Fork(n) runs the benchmark in n fresh JVM processes. Forking isolates each run from JIT profiles built up by previous benchmarks, improving reproducibility. The default is one fork.
import org.openjdk.jmh.annotations.*;
@Fork(2)
public class Bench {
@Benchmark
public long now() {
return System.nanoTime();
}
}Launching the Runner
You start benchmarks via a main that configures an Options object and a Runner, or via the generated executable JAR. The include(...) regex selects which benchmarks to run.
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.*;
public class Launcher {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include("Bench")
.build();
new Runner(opt).run();
}
}Reading the Output
JMH prints a table with the benchmark name, mode, sample count, the score, the score error, and units, for example: Bench.work avgt 25 3.142 +/- 0.011 ns/op. The +/- is the confidence interval.
Keep Benchmarks Focused
Each benchmark should measure one thing. Mixing setup, I/O, and the operation under test muddies the result. Move preparation into @Setup methods (covered with state) so only the hot path is timed.
Quick Check
Test your understanding of writing benchmarks.
Recap
You learned how to write a JMH benchmark:
- Annotate a method with @Benchmark and return the result.
- @BenchmarkMode picks Throughput, AverageTime, SampleTime, or SingleShotTime.
- @OutputTimeUnit sets readable units; @Fork isolates runs in fresh JVMs.
- Launch with a Runner + Options or the generated JAR.
- Keep each benchmark focused on a single hot path.
Frequently asked questions
Is the “Writing a Benchmark” lesson free?
Yes — the full text of “Writing a Benchmark” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.
What will I learn in “Writing a Benchmark”?
@Benchmark and modes. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Java Academy?
No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Writing a Benchmark” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Java Academy lesson?
Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Why JMH
- Writing a Benchmark
- Warmup and Iterations
- Avoiding Dead-Code Elimination