JUring is a Java library that provides bindings to Linux's io_uring asynchronous I/O interface using Java's Foreign Function & Memory API. JUring can deliver significant performance improvements over standard Java FileChannel operations, particularly for high-throughput file I/O workloads.
JUring with registered files provides the following performance:
All benchmarks were conducted on a Linux machine using JMH (Java Microbenchmark Harness) with 2,211 operations per test invocation.
Comparing registered files vs pre-opened FileChannels:
| Buffer Size | Registered Files (ops/ms) | Pre-opened FileChannels (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 29,023 | 18,769 | +55% |
| 4KB | 13,393 | 2,275 | +489% |
| 16KB | 679 | 554 | +23% |
| 64KB | 150 | 129 | +16% |
Comparing different I/O approaches with open/read/close patterns:
| Buffer Size | JUring Open/Read/Close (ops/ms) | FileChannel Open/Read/Close (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 1,252 | 968 | +29% |
| 4KB | 1,268 | 855 | +48% |
| 16KB | 563 | 445 | +27% |
| 64KB | 141 | 125 | +13% |
The goal of this benchmark is to open a file, read the given buffer size, and close it again. Opening and closing the files is the heavy part of this benchmark.
Comparing JUring blocking vs FileChannel with Virtual Threads:
| Buffer Size | JUring Blocking + VThreads (ops/ms) | FileChannel + VThreads (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 1,051 | 923 | +14% |
| 4KB | 1,029 | 710 | +45% |
| 16KB | 788 | 350 | +125% |
| 64KB | 286 | 120 | +138% |
JUring registered files vs pre-opened FileChannels across different thread counts:
Single Thread:
| Buffer Size | JUring (ops/ms) | FileChannel (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 891 | 400 | +123% |
| 4KB | 860 | 260 | +231% |
| 16KB | 498 | 144 | +246% |
| 64KB | 151 | 53 | +185% |
8 Threads:
| Buffer Size | JUring (ops/ms) | FileChannel (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 4,292 | 2,429 | +77% |
| 4KB | 3,013 | 1,724 | +75% |
| 16KB | 1,189 | 895 | +33% |
| 64KB | 286 | 294 | -3% |
20 Threads:
| Buffer Size | JUring (ops/ms) | FileChannel (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 5,200 | 5,204 | 0% |
| 4KB | 3,381 | 3,440 | -2% |
| 16KB | 1,211 | 1,449 | -16% |
| 64KB | 233 | 346 | -33% |
JUring excels in scenarios with:
Consider standard FileChannel for:
The benchmarks use JMH (Java Microbenchmark Harness) with the following configuration:
registeredFiles: io_uring with pre-registered file descriptors (optimal performance)preOpenedFileChannels: FileChannel with pre-opened file handlesjuringOpenReadClose: JUring with full open/read/close cyclefileChannelOpenReadClose: FileChannel with full open/read/close cyclejuringBlockingWithVirtualThreads: JUring blocking API with Virtual ThreadsfileChannelOpenReadCloseOnVirtualThreads: FileChannel with Virtual ThreadsFor complete benchmark source code and detailed methodology, see the test files in the repository src/test/java/bench/random.
If you want to run the benchmark yourself, you can use the following:
seq 1 2211 | xargs -P 8 -I {} bash -c 'yes "{} " | head -c 5242880 > "file_{}.bin"'
Java
99.8%
JUring is a Java library that provides bindings to Linux's io_uring asynchronous I/O interface using Java's Foreign Function & Memory API. JUring can deliver significant performance improvements over standard Java FileChannel operations, particularly for high-throughput file I/O workloads.
JUring with registered files provides the following performance:
All benchmarks were conducted on a Linux machine using JMH (Java Microbenchmark Harness) with 2,211 operations per test invocation.
Comparing registered files vs pre-opened FileChannels:
| Buffer Size | Registered Files (ops/ms) | Pre-opened FileChannels (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 29,023 | 18,769 | +55% |
| 4KB | 13,393 | 2,275 | +489% |
| 16KB | 679 | 554 | +23% |
| 64KB | 150 | 129 | +16% |
Comparing different I/O approaches with open/read/close patterns:
| Buffer Size | JUring Open/Read/Close (ops/ms) | FileChannel Open/Read/Close (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 1,252 | 968 | +29% |
| 4KB | 1,268 | 855 | +48% |
| 16KB | 563 | 445 | +27% |
| 64KB | 141 | 125 | +13% |
The goal of this benchmark is to open a file, read the given buffer size, and close it again. Opening and closing the files is the heavy part of this benchmark.
Comparing JUring blocking vs FileChannel with Virtual Threads:
| Buffer Size | JUring Blocking + VThreads (ops/ms) | FileChannel + VThreads (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 1,051 | 923 | +14% |
| 4KB | 1,029 | 710 | +45% |
| 16KB | 788 | 350 | +125% |
| 64KB | 286 | 120 | +138% |
JUring registered files vs pre-opened FileChannels across different thread counts:
Single Thread:
| Buffer Size | JUring (ops/ms) | FileChannel (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 891 | 400 | +123% |
| 4KB | 860 | 260 | +231% |
| 16KB | 498 | 144 | +246% |
| 64KB | 151 | 53 | +185% |
8 Threads:
| Buffer Size | JUring (ops/ms) | FileChannel (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 4,292 | 2,429 | +77% |
| 4KB | 3,013 | 1,724 | +75% |
| 16KB | 1,189 | 895 | +33% |
| 64KB | 286 | 294 | -3% |
20 Threads:
| Buffer Size | JUring (ops/ms) | FileChannel (ops/ms) | Improvement |
|---|---|---|---|
| 512 bytes | 5,200 | 5,204 | 0% |
| 4KB | 3,381 | 3,440 | -2% |
| 16KB | 1,211 | 1,449 | -16% |
| 64KB | 233 | 346 | -33% |
JUring excels in scenarios with:
Consider standard FileChannel for:
The benchmarks use JMH (Java Microbenchmark Harness) with the following configuration:
registeredFiles: io_uring with pre-registered file descriptors (optimal performance)preOpenedFileChannels: FileChannel with pre-opened file handlesjuringOpenReadClose: JUring with full open/read/close cyclefileChannelOpenReadClose: FileChannel with full open/read/close cyclejuringBlockingWithVirtualThreads: JUring blocking API with Virtual ThreadsfileChannelOpenReadCloseOnVirtualThreads: FileChannel with Virtual ThreadsFor complete benchmark source code and detailed methodology, see the test files in the repository src/test/java/bench/random.
If you want to run the benchmark yourself, you can use the following:
seq 1 2211 | xargs -P 8 -I {} bash -c 'yes "{} " | head -c 5242880 > "file_{}.bin"'
Java
99.8%