Lab / Open methodology
Java 8 → 25: parallelizing an order integration
256 orders completed: 2.95 s → 380.91 ms. Synthetic lab; median of 10 runs. Open code and raw data.
Java 8 · sequential callstoJava 25 · virtual threads
Java 8 → 25 LAB MEASUREMENT
One order, three services. Stop stacking the waits.
Prepare an order using price, stock and shipping responses. We measured runtime migration and concurrent workflow changes separately against identical order results.
Clear a peak-time order queue sooner. Run independent tasks together rather than occupying a worker while each service responds.
Java 8 · sequential calls
8 workers; wait for three independent services sequentially per order.
- CPU time
- 259.207 ms
- Peak platform threads
- 12
Java 25 · unchanged old code
Same bytecode and same 8 workers. Only the runtime changed.
- CPU time
- 256.989 ms
- Peak platform threads
- 14
Java 25 · parallel platform control
Parallel calls; 64 platform workers and a 64-call dependency limit.
- CPU time
- 108.114 ms
- Peak platform threads
- 70
Java 25 · virtual threads
Parallel independent calls; same 64-call limit, one virtual thread per task.
- CPU time
- 125.21 ms
- Peak platform threads
- 18
Bars start at zero and share the same time scale across implementations.
Split independent service calls and start them together. Java 25 virtual threads carry waiting tasks on fewer platform threads. The matched platform-pool control shows similar speed with a different thread footprint.
All load points and measurements
| Implementation | Median duration | CPU time | Peak platform threads |
|---|---|---|---|
| Java 8 · sequential calls | 182.873 ms | 25.94 ms | 12 |
| Java 25 · unchanged old code | 184.777 ms | 18.021 ms | 14 |
| Java 25 · parallel platform control | 31.538 ms | 11.909 ms | 70 |
| Java 25 · virtual threads | 31.61 ms | 10.142 ms | 18 |
| Implementation | Median duration | CPU time | Peak platform threads |
|---|---|---|---|
| Java 8 · sequential calls | 729.54 ms | 52.624 ms | 12 |
| Java 25 · unchanged old code | 725.443 ms | 65.806 ms | 14 |
| Java 25 · parallel platform control | 97.516 ms | 29.633 ms | 70 |
| Java 25 · virtual threads | 97.451 ms | 42.585 ms | 18 |
| Implementation | Median duration | CPU time | Peak platform threads |
|---|---|---|---|
| Java 8 · sequential calls | 2.95 s | 259.207 ms | 12 |
| Java 25 · unchanged old code | 2.93 s | 256.989 ms | 14 |
| Java 25 · parallel platform control | 399.298 ms | 108.114 ms | 70 |
| Java 25 · virtual threads | 380.91 ms | 125.21 ms | 18 |
CPU cost at your workload
Compare the recorded CPU time at your own monthly volume.
One batch run = 256 Orders submitted together.
CPU time reduced / month0.3722 hours
Processing cost difference / month—Calculated after you enter a unit price.
Lab CPU time × your volume and unit price. This is not a hosting bill forecast; idle capacity, networking, storage, licences and migration are excluded.
Try it yourself
Replay the recorded lab results side by side.
As the workload grows
Duration by workload
- Before
- After
Duration by workload (ms)
Show as a table
| Orders submitted together | Before | After |
|---|---|---|
| 16 | 182.87 ms | 31.61 ms |
| 64 | 729.54 ms | 97.45 ms |
| 256 | 2,949.73 ms | 380.91 ms |
How we measured
Environment, protocol and technical analysis
Environment and data
- Environment
- Apple M3 · 8 cores · 24 GiB · macOS · native arm64 · shared developer workstation
- Dataset
- 16/64/256 synthetic orders requiring three independent service calls. Every complete result array matches an independent Python calculation.
- Tools
- Corretto 8u432 · Corretto 25.0.3 · -Xms128m -Xmx128m -XX:+UseG1GC · Python output oracle
- Repetitions
- 140 fresh JVM runs: 3 loads × 4 implementations × 10 repeats plus 20 constrained-service controls. At least 2s warmup, fixed randomized order.
One order, three services. Stop stacking the waits.
Prepare an order using price, stock and shipping responses. We measured runtime migration and concurrent workflow changes separately against identical order results.
Same Java 8 bytecode on both JDKs, identical synthetic outputs and dependency service. Sequential pool of 8, Java 25 runtime-only control and matched 64-call platform/virtual arms. Additional dependency-capacity-8 control; all 140 runs published. Primary point of 256 orders selected before measurement. Duration covers complete batch completion; platform threads are the median ThreadMXBean peak.
Inspect the measurement script ↗What changes for the business?
Clear a peak-time order queue sooner. Run independent tasks together rather than occupying a worker while each service responds.
Change and scope
Split independent service calls and start them together. Java 25 virtual threads carry waiting tasks on fewer platform threads. The matched platform-pool control shows similar speed with a different thread footprint.
Synthetic order workflow with real loopback TCP calls. Common 25 ms service-delay model and capacity of 64 calls. Size means orders submitted together, not live users. CPU covers the client JVM only; platform-thread count excludes virtual tasks.
The dependency needs capacity too
We also limited the service to 8 concurrent calls. At 256 orders, the old implementation took 2936.0 ms and virtual-thread implementation 2777.3 ms. Once the bottleneck moves to the dependency, concurrency in the caller is not enough. All controls remain in the raw package.
Which post-Java-8 capabilities do we assess?
| Capability | Business relevance | Relation to this test |
|---|---|---|
| Virtual threads · Java 21 | Run many waiting integration tasks on fewer platform threads | Measured alongside a matched platform-pool control |
| synchronized pinning improvement · Java 24 | Avoid holding carrier threads during I/O waits inside synchronized code | Assess during discovery; not the cause claimed for this ratio |
| Compact Strings · Java 9 | Smaller String storage for suitable text-heavy data | Requires a separate heap profile; not measured here |
| Current JDK and dependency maintenance | Maintain a workable patch, observability and deployment process | Test security findings and compatibility for each project |
The previous identical-bytecode CPU experiment remains available. It isolates the runtime rather than the workflow change measured here.
Where to start in your system
Identify the slow operation, data volume and peak workload. Establish its baseline, change the code and access pattern, then compare the same result.
What we did
Business rule and data
AIPrepared the synthetic workflow, tests and measurement automation.
VerificationPublished code and raw outputs are available for review; this is not a client project.
Implementation change
AISplit independent service calls and start them together. Java 25 virtual threads carry waiting tasks on fewer platform threads. The matched platform-pool control shows similar speed with a different thread footprint.
VerificationOutput equivalence was independently checked; every repetition is retained.