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.

CompletedSMBEnterprisePartners

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.

Business effect

Clear a peak-time order queue sooner. Run independent tasks together rather than occupying a worker while each service responds.

BEFOREJava 8 · sequential calls
MODERNIZEDJava 25 · virtual threads
Orders submitted together256
16Recorded loads only256
Actual time scale
SAME TASK · SAME DATA10 runs · median
01

Java 8 · sequential calls

8 workers; wait for three independent services sequentially per order.

2.95 s
CPU time
259.207 ms
Peak platform threads
12
02

Java 25 · unchanged old code

Same bytecode and same 8 workers. Only the runtime changed.

2.93 s
CPU time
256.989 ms
Peak platform threads
14
03

Java 25 · parallel platform control

Parallel calls; 64 platform workers and a 64-call dependency limit.

399.298 ms
CPU time
108.114 ms
Peak platform threads
70
04

Java 25 · virtual threads

Parallel independent calls; same 64-call limit, one virtual thread per task.

380.91 ms
CPU time
125.21 ms
Peak platform threads
18

Bars start at zero and share the same time scale across implementations.

Completion time reduced87.1%Time difference: 2.569 sOriginal → modernized implementation
What changed?

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
16 · Orders submitted together
ImplementationMedian durationCPU timePeak platform threads
Java 8 · sequential calls182.873 ms25.94 ms12
Java 25 · unchanged old code184.777 ms18.021 ms14
Java 25 · parallel platform control31.538 ms11.909 ms70
Java 25 · virtual threads31.61 ms10.142 ms18
64 · Orders submitted together
ImplementationMedian durationCPU timePeak platform threads
Java 8 · sequential calls729.54 ms52.624 ms12
Java 25 · unchanged old code725.443 ms65.806 ms14
Java 25 · parallel platform control97.516 ms29.633 ms70
Java 25 · virtual threads97.451 ms42.585 ms18
256 · Orders submitted together
ImplementationMedian durationCPU timePeak platform threads
Java 8 · sequential calls2.95 s259.207 ms12
Java 25 · unchanged old code2.93 s256.989 ms14
Java 25 · parallel platform control399.298 ms108.114 ms70
Java 25 · virtual threads380.91 ms125.21 ms18
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)

01,0002,0003,00016642562,949.73 ms380.91 ms

Select a data point

01,0002,0003,0001664256380.91 ms

Select a data point

Orders submitted togetherMarkers: measured points
Show as a table
Duration by workload
Orders submitted togetherBeforeAfter
16182.87 ms31.61 ms
64729.54 ms97.45 ms
2562,949.73 ms380.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.
Open raw measurement data ↗

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

  1. 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.

  2. 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.