> Fray also provides deterministic replay capabilities for debugging specific thread interleavings. Fray is designed to be easy to use and can be integrated into existing testing frameworks.
I wish I had this 20 years ago.
Looks like fixing the underlying bug is still in-progress, [1] I wonder how many lines of code it will take.
[0] https://github.com/aoli-al/jdk/commit/625420ba82d2b0ebac24d9...
You make it sound like there is some modern development superseding what java has, but that's absolutely not the case.
Like even rust is just pretty much a no-overhead `synchronized` on top of an object. It is necessary there, because data races are a fundamental memory safety issue, but Java is immune to that (it has "safe" data races). Logical bugs can trivially happen in either case - as an easy example even if all your fields are atomically mutated, the whole object may not make sense in certain states, like a date with February the 31st. Rust does nothing against such, and concurrent data structures have ample grounds for realistic examples of the above.
STM.
The terms 'atomic', 'thread-safe', and 'concurrent' collections are thrown around too loosely for application programmers IMO, for exactly your example above.
In other scenarios, 'atomics' refer to the ability to do one thing atomically. With STM, you can do two or more things atomically.
Likewise with 'thread-safe'. Thread-safe seems to indicate that the object won't break internally in the presence of multiple threads, which is too low of a bar to clear if your goal is to write an actually thread-safe application out of so-called 'thread-safe' parts.
STM has actual concurrent data structures, where you can write straight-line code like 'if this collection has at least 5 elements, then pop one'.
I don't think the Feb 31 example is that fair though, because if you want to construct a representation of Feb 31, who's going to stop you? And if you don't want to, plain old static types is the solution.
"Make invalid states unrepresentable" - it's bad design that February the 31st is a thing in your data structure when that's invalid. You can't always avoid this, but it's appalling how bad most people's data structures are.
C's stdlib provides a tm structure in which day of the week is stored in a signed 32-bit integer. You know, for when it's the negative two billionth day of the week...
Oh my ... you never seen a proper Actor language, have you?
Have a look at Erlang and Pony, for starters. It will open your mind.
This in particular is great: https://www.ponylang.io/discover/what-makes-pony-different/#...
> Pony doesn’t have locks nor atomic operations or anything like that. Instead, the type system ensures at compile time that your concurrent program can never have data races. So you can write highly concurrent code and never get it wrong.
This is what I am talking about.
> You make it sound like there is some modern development superseding what java has, but that's absolutely not the case.
Both Actor-model languages and Rust (through a surprisingly different path: tracking aliases and lifetimes) do something that's impossible in Java (and most languages): prevent data races due to improper locking (as mentioned above, if your language even has locks and it doesn't make them safe like Rust does, you know you're going to have a really hard time. actor-languages just eliminate locks, and "manual concurrency", completely). Other kinds of races are still possible, but preventing data races go a very, very long way to making concurrency safe and easy.
I guess there there are language features like co-routines/co-operative multi-tasking that make certain algorithms possible, but nothing about Java prevents implementing sound concurrency algorithms in general.
You wouldn't make that claim if your language didn't have locks.
Separately, we're looking at using fray for concurrency property testing, as a way to reliably catch concurrency issues in a distributed system by simulating it within a single JVM.
edit: for some reason the author overrode the background color on code blocks via an inline style of
background-color:#f0f0f0
from var(--code-background-color) = #f2f2f2
to make the background nigh imperceptibly darker, but then while the stylesheet properly switches the to #01242e in dark mode the inline override stays and blows it to bit.Not that it's amazing if you remove the inline stle, on account of operators and method names being styled pretty dark (#666 and #4070a0).
I wonder how this works when one runs test in parallel (something I always enable in any project). By this I mean configuring JUnit to run as many tests as cores are available to speed up the run of the whole test suite.
I took a peek at the code and I have the impression it doesn't work that well as it hooks into when a thread is started. Also, I'm not sure if this works with fibers.
Fray currently does not support virtual threads. We do have an open issue tracking it, but it is low priority.
[1]: https://docs.gradle.org/current/userguide/java_testing.html#...
In the technical paper, Section 5.4 you mention that kotlin has non-determinism in the scheduler. Where does this non-determinism come from?
It seems unclear to me why Kotlin would inject randomness here, and I suspect that you may actually have identified a false positive in the Lincheck DSL.
In our paper, we found that Fray suffers from false negatives because of this missing feature. Lincheck supports Kotlin coroutines so it finds one more bug than Fray in LC-Bench.
We didn't make any claims about false positives in Lincheck.
To be clear, I made that claim :) I agree that the paper makes no such claim.