Writing a Benchmark
@Benchmark and modes.
Writing a Benchmark is a free Java Academy lesson on CoddyKit. This is 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, and your progress syncs across the web and the CoddyKit app. The Java Academy course includes 4 lessons in total.
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.
Learn Java with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 104
- Lessons
- 374
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. 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. The Java Academy course includes 4 lessons in total.
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, so you can start here or from the beginning and move at your own pace. This is lesson 2 of 4.
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