Matching C#'s volatile semantics with VarHandle

Jun 26, 2026

A great thread explaining how volatile in Java and C# offer different memory ordering semantics. Java offers sequentially consistent semantics for volatile accesses, whereas C# offers acquire/release semantics.

I wondered if Java offered a way to weaken the volatile semantics to match C#’s. And it turned out it does: VarHandle. VarHandle allows you to have a finer control of the memory ordering of variables. I’ve set up a jcstress test to verify how many r1 = r2 = 0 we’d get on plain access, volatile access, and under acquire/release semantics. Here are the results:

Variant 0, 0 0, 1 1, 0 1, 1 0,0 verdict
Plain10,689,870269,116,842121,776,634260ACCEPTABLE_INTERESTING
AcqRel9,383,746218,844,266116,334,95065,882ACCEPTABLE_INTERESTING
Volatile0173,087,21674,618,180517,792FORBIDDEN

There’s not much difference between Plain and AcqRel, because our test isn’t able to capture that change. So I set up another litmus test

Litmus Test: Message Passing
Can this program see r1 = 1, r2 = 0?

    // Thread 1           // Thread 2
    x = 1                 r1 = y
    y = 1                 r2 = x

as evidence that Plain is weaker than AcqRel, which in turn, from the first test, is weaker than Volatile. Results:

Variant 0, 0 0, 1 1, 0 1, 1 1,0 verdict
Plain14,804,66842,2866,410399,332,668ACCEPTABLE_INTERESTING
AcqRel36,308,51476,0400391,123,666FORBIDDEN
Volatile108,338,69818,7720271,831,446FORBIDDEN

TBH, I’m not an expert on the exact orderings allowed by each of these semantics. This post is just a reminder for me to be aware that ordering exists and can be fine-tuned.

#java #csharp #concurrency #memory-model #memory-ordering #jcstress