Benchmark with JMH and Gradle

JMH stands for Java Microbenchmark Harness. JMH is a tool that makes benchmarking more accurate and straightforward.
Benchmarking is extremely useful for high-performance applications, helping you choose the algorithm or library that delivers the best speed.

Alright! Enough with the theory, let’s get into practice. What we need to do is build a project comparing the speed of different string concatenation approaches in Java. Make sure you have Java and Gradle installed first!

Step 1: Create a Gradle project

Open Terminal and run the following command:
gradle init
Then select the following options:

Select type of project to generate:
  1: basic
  2: groovy-application
  3: groovy-library
  4: java-application
  5: java-library
  6: kotlin-application
  7: kotlin-library
  8: scala-library
Enter selection (default: basic) [1..8] 4

Select build script DSL:
  1: groovy
  2: kotlin
Enter selection (default: groovy) [1..2] 1

Select test framework:
  1: junit
  2: testng
  3: spock
Enter selection (default: junit) [1..3] 1

Project name (default: jmh-gradle-example):
Source package (default: jmh.gradle.example): tri.le.jmh

Step 2: Copy the main directory to jmh

cp -r src/main src/jmh
The purpose of this is to separate the 3 parts: main code, test code, and benchmark code.

Step 3: Update build.gradle

Add id "me.champeau.gradle.jmh" version "0.4.8" to the plugins block.

Step 4: Setup is done, now let’s write code ;))

To make it quick, you can grab this file, and I will explain right away:

1
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)

Performs “warmup” 5 times, 1 second each. Why do we need warmup? Java automatically optimizes code, so warming up helps us achieve accurate benchmark results.

1
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)

Executes the benchmark over 5 iterations, 1 second each.

1
2
@Fork(1)
@State(Scope.Thread)

JMH will create 1 child process for each benchmark case. Creating a child process ensures the optimizer is reset and the benchmark results are more accurate.

Step 5: Run the benchmark!

./gradlew --no-daemon clean jmh
The results will be displayed in the console or can be viewed with:
cat build/reports/jmh/results.txt

Benchmark                           Mode  Cnt         Score        Error  Units
StringAppend.bmStringBuffer        thrpt    5  13566863.267 ± 427443.554  ops/s
StringAppend.bmStringBufferx1000   thrpt    5     36998.492 ±   2895.325  ops/s
StringAppend.bmStringBufferx5      thrpt    5   5529261.499 ± 277625.096  ops/s
StringAppend.bmStringBuilder       thrpt    5  13462457.325 ± 978240.749  ops/s
StringAppend.bmStringBuilderx1000  thrpt    5     36989.126 ±   1716.705  ops/s
StringAppend.bmStringBuilderx5     thrpt    5   5466705.447 ± 176616.966  ops/s
StringAppend.bmStringConcat        thrpt    5  27930719.298 ± 581249.324  ops/s
StringAppend.bmStringConcatx1000   thrpt    5     47104.039 ±   2358.121  ops/s
StringAppend.bmStringConcatx5      thrpt    5   7170529.805 ± 383608.303  ops/s
StringAppend.bmStringJoin          thrpt    5  10204201.921 ± 463528.750  ops/s
StringAppend.bmStringJoinx1000     thrpt    5     30493.885 ±   1708.261  ops/s
StringAppend.bmStringJoinx5        thrpt    5   4322622.068 ±  49032.328  ops/s
StringAppend.bmStringPlus          thrpt    5  13689364.101 ± 509784.615  ops/s
StringAppend.bmStringPlusx1000     thrpt    5       288.086 ±     15.175  ops/s
StringAppend.bmStringPlusx5        thrpt    5   5590364.456 ± 277476.212  ops/s

You can also check out the git repo here. :))

updatedupdated2026-09-052026-09-05
Load Comments?