Flurry: Java's ConcurrentHashMap semantics reimplemented in Rust
A port of Java's ConcurrentHashMap to Rust
At a glance
- What is it?
- Flurry is a Rust port of java.util.concurrent.ConcurrentHashMap that keeps the Java API shape, including compute, merge, compute_if_absent and the computeIfPresent-style methods, while using parking_lot, seize and ahash underneath. It suits a Rust developer who wants Java's concurrent map semantics, and the project itself points you at papaya or dashmap if throughput matters.
- Who is it for?
- Flurry fits a Rust codebase that is porting logic written against Java's ConcurrentHashMap and wants the same method names and semantics without reimplementing the concurrency model, since the port follows the JSR166 source closely and ships the original Java files under jsr166/ for comparison.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A port with the original Java kept alongside it
Flurry is described in one line as a port of Java's java.util.concurrent.ConcurrentHashMap to Rust, and the readme explains where the port came from in unusual detail. It is based on the public domain source file from JSR166 as of CVS revision 1.323, the Java Concurrency Interest working group where ConcurrentHashMap was developed. The Java source files are included under the jsr166/ subdirectory for easy reference, and the Cargo manifest excludes that directory from the published package.
Keeping the original in the tree is the interesting engineering decision here. A port that only keeps the Rust result is a port you have to trust. A port that keeps the Java next to it is one where you can open two files and check that a branch in one matches a branch in the other. For a data structure whose entire value is in the correctness of its memory ordering and its lock-free read path, that reference matters more than for most ports.
There is also a history of how it was built. The port was developed as part of a series of live coding streams, and the readme links the YouTube playlist and the tweet that kicked it off. So the provenance is public and dated rather than a quiet contribution, which is relevant if you are judging how much scrutiny the code has received.
The readme also links the upstream tests from the OpenJDK repository, which suggests the test suite is ported from the Java original rather than written fresh.
The crate is Apache-2.0 at the repository level in the metadata, with the Cargo manifest declaring license = "MIT OR Apache-2.0". Both licence files sit at the root, LICENSE-APACHE and LICENSE-MIT, and the dual licensing exists to match the Rust API guidelines requirement that a crate have a permissive licence. The Java sources are public domain, which is why they can be included.
Java's API surface, including the parts Rust has no syntax for
The whole premise of a port like this is that you can read Java code and know what the Rust equivalent does. Flurry is not a generic concurrent map with a Rust-flavoured interface. It is the Java API, method names and semantics included.
That includes the compute family. Java's ConcurrentHashMap has computeIfAbsent, computeIfPresent and compute, which perform a read, a mutation and a write as a single atomic operation on a bin, and it has merge for the read-modify-write of an existing value against a default. Those methods exist because Java's Map interface has no way to express an atomic update, so the Java API grew a set of methods that other languages do not have. A Rust port that dropped them would not be usable as a drop-in for Java code, and Flurry keeps them.
The corollary is that the Rust API has some awkward corners that Java does not, and those are worth knowing before you migrate. Java's compute family takes a BiFunction, which in Rust means a closure with a signature that returns an Option, since Java's null is a value there and an absence in Rust. The null-handling differences are the part that catches people out when code is ported line by line.
The Cargo keywords are hashmap, concurrent and map, and the categories are concurrency and data-structures, which places it in the same shelf as any other lock-based map in the ecosystem rather than as a general database.
What the port does not do is extend the map beyond Java's. There is no persistence, no sharding across processes, no string interning, no ordering guarantee beyond what the map provides, and no attempt to be a Java virtual machine compatibility layer.
What sits underneath: parking_lot, seize and ahash
The dependency list is short and tells you the design.
The synchronization is parking_lot 0.12, which is a spinlock-based locking primitive with generally better behaviour under contention than the standard library's mutex, and seize 0.3.3, which is the epoch-based reclamation library used to safely free memory once no thread can still observe it. Seize is the piece that makes a lock-based concurrent map with real deletion safe: without deferred reclamation, freeing a value while another thread is mid-read is a use-after-free, and epoch-based reclamation is one of the two standard answers to that problem in Rust.
The hashing is ahash 0.8.4, configured with default-features = false and features = ["compile-time-rng"]. The comment in the manifest explains the reasoning: enabling just the compile-time random number generator gives a reasonable ahash::RandomState::default without also forcing consumers of flurry into using a runtime random number generator. Consumers who want runtime randomness can still opt into that feature, and it takes precedence over compile-time-rng as the ahash documentation specifies. This is a small piece of care that shows up in the dependency graph of every project that uses flurry.
num_cpus 1.12.0 is there for the same reason Java's implementation needs it, to size the per-processor structures.
Three features are optional. rayon 1.3 provides parallel iteration. serde 1.0.105 provides serialisation. And a regex dependency is declared under a target of cfg(any()) with the comment that it exists for minimal-versions testing, which is a technique where the resolver is forced to pick the lowest permitted version of every dependency to catch accidental upper bounds.
The dev-dependencies are rand 0.8, rayon, criterion 0.5 and serde_json 1.0.50, with criterion being the benchmarking harness.
Benchmarks against dashmap and hashbrown, and what they are for
The Cargo manifest declares two benchmarks with harness = false, so they run under criterion rather than the built-in test harness: flurry_dashmap and flurry_hashbrown.
Both comparisons are chosen deliberately. dashmap is the closest competitor in the Rust ecosystem, a sharded concurrent map built on similar ideas. hashbrown is the SwissTable-based hash map that Rust's standard library HashMap is built on, and it is a useful non-concurrent baseline. So the benchmark suite answers two different questions: how Flurry compares with another concurrent map, and how much of the cost is concurrency itself rather than hashing.
The results are not published in the readme, so the numbers are in the repository's benchmark output rather than in the documentation. What the readme does publish is the conclusion, and it is not favourable: Flurry currently suffers performance and memory usage issues under load, and the readme suggests considering papaya or dashmap if this matters.
That admission is the most useful line in the whole readme for an evaluating engineer, and it should shape the evaluation. A concurrent map is chosen for its behaviour under contention, so a project that says it struggles under load is telling you its main selling point is the API shape, not the throughput.
The difference in approach between the alternatives is worth spelling out. dashmap partitions the keyspace into fixed shards, each with its own lock and its own map, which spreads contention across cores at the cost of operations spanning shards. papaya is built around a segmented design with a concurrent registration mechanism, and it targets the same use case with a different trade-off in the read path. The practical difference between them and Flurry is not the API, since all three give you a map, it is what happens to your thread when the map is busy.
Using Flurry in a project, and where to read the docs
Flurry is published on crates.io under the name flurry, and the API documentation is on docs.rs. The readme itself carries almost no usage example, which is unusual for a data structure crate and tells you the documentation is the reference rather than the README.
Since the readme gives no install command, the two places the project points to for the details are the crates.io page linked from the badges and the docs.rs documentation linked beside it. The badges at the top of the readme are exactly those two links, alongside the Codecov coverage report, the deps.rs dependency status page and the Azure DevOps pipeline badge.
The repository layout matches a crate with a serious testing setup: src/ for the implementation, tests/ for the integration tests, benches/ for the criterion benchmarks, a jsr166/ directory with the original Java sources, and a set of configuration files that describe how the project is checked. There is codecov.yml for coverage reporting, deny.toml for cargo-deny, which checks dependency licences and advisories, and lsan-suppressions.txt, which is the LeakSanitizer suppression list used when the test suite runs under sanitizers. rustfmt.toml pins formatting, and a CHANGELOG.md records the release history.
The Cargo manifest is marked experimental with a maintenance badge reading status = "experimental", which in the Rust ecosystem is a crates.io flag meaning the crate is not considered stable for production use. The version is 0.5.2, on edition 2021, authored by Jon Gjengset, with the description recorded as Rust port of Java's ConcurrentHashMap and the repository pointing at github.com/jonhoo/flurry.git.
One practical consequence of the Rust API guidelines: crates.io requires a package name without a hyphen, and flurry is short enough that a name collision on the registry was a real possibility, which is part of why the author chose it.
Where Flurry is the wrong choice
The first limitation is stated by the project itself and should not need restating: Flurry suffers performance and memory usage issues under load. The readme tells you to consider papaya or dashmap if that matters. If your workload is a hot map written by many threads, choosing Flurry over those alternatives means choosing the Java API shape over the throughput, and that is a trade you have to make deliberately.
The second is the experimental flag and the version number. The Cargo manifest declares the project as experimental and the version is 0.5.2, which under SemVer means no stability guarantee. There are no GitHub releases published for the repository, so the version history lives in the crate registry and in the CHANGELOG rather than in tagged releases. The last push was on 2026-04-06, which is more than six months before the current date, so this is not a project with a recent stream of fixes.
The third is the semantic gap that a Java compatibility target creates. Java's ConcurrentHashMap is a Java API with Java's null semantics, Java's Map interface contract and Java's memory model. Rust's Option is not Java's null, and a closure returning Option in the compute family is a Rust convention that has nothing to do with Java. Code that relies on the Java behaviour around null values, particularly a compute function that returns null to mean no change, has to be translated rather than moved across.
The fourth is that a port inherits the original's scope, not the ecosystem's. ConcurrentHashMap is a single-process, in-memory structure with no persistence and no distribution. If what you actually need is a shared map across processes, or durability across restarts, or a cache with eviction policy, no amount of API fidelity to Java helps, and a database or a purpose-built cache is the right category of tool.
The fifth is the licensing of the derived code. The port is dual licensed MIT or Apache-2.0, and the contribution terms state that any contribution is dual licensed on the same terms unless the contributor says otherwise. The included Java sources are public domain, which is what makes the inclusion safe. That arrangement is clean, but it does mean you are shipping a crate whose provenance is a specific CVS revision of a specific file, and any future upstream change is not automatically picked up.
Editorial conclusion
Flurry fits a Rust codebase that is porting logic written against Java's ConcurrentHashMap and wants the same method names and semantics without reimplementing the concurrency model, since the port follows the JSR166 source closely and ships the original Java files under jsr166/ for comparison. It is the wrong choice if throughput under load is the goal, because the readme states plainly that Flurry suffers performance and memory usage issues under load and names papaya and dashmap as alternatives. Before adopting it, decide between the two crate-level alternatives the readme points at, note that the crate version is 0.5.2, that the Cargo manifest marks the project as experimental, and that the last push was on 2026-04-06 with no GitHub releases published.
Frequently asked questions
What is Flurry in Rust?
Flurry is a port of Java's java.util.concurrent.ConcurrentHashMap to Rust, based on the public domain JSR166 source file as of CVS revision 1.323. The original Java files are kept under the jsr166/ subdirectory for reference, and the crate is published on crates.io as flurry.
Does Flurry support Java's compute and merge methods?
Yes. The port keeps Java's API shape, including the compute family of computeIfAbsent, computeIfPresent and compute, along with merge, because those exist in Java to perform an atomic read-modify-write on a bin. The Rust versions take closures rather than Java's BiFunction, so the null handling translates as an Option rather than a null value.
What is Flurry faster or slower than?
The readme states that Flurry currently suffers performance and memory usage issues under load and suggests papaya or dashmap as alternatives if that matters. The Cargo manifest defines two criterion benchmarks with harness = false, one comparing against dashmap and one against hashbrown, so the comparison code is in the repository even though the numbers are not published in the readme.
What licence is Flurry released under?
Dual licensed under Apache-2.0 and MIT at your option, with LICENSE-APACHE and LICENSE-MIT in the repository root and license = "MIT OR Apache-2.0" in the Cargo manifest. The bundled Java sources are public domain, which is what allows them to be included.
Is Flurry ready for production use?
The Cargo manifest marks the project as experimental with a maintenance badge reading status = "experimental", and the version is 0.5.2. The repository publishes no GitHub releases, and the last push was on 2026-04-06.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jonhoo-flurry)Was this useful?