Java Concurrency
Under The Hood

#volatile #membar #dragons #openjdk

#jmm #store #load #internals

#cachecoherency #omg

#javaone #jug

Gleb Smirnov

me@gvsmirnov.ru

Leaky Abstractions

void executedOnCpu0() {
    value = 10;
    finished = true;
}
void executedOnCpu1() {
    while(!finished);
    assert value == 10;
}

Can the assertion fail?

What if it's ran on x86?

The Theoretical Approach

Thus Spoke JMM

A write to a volatile variable

happens-before

All subsequent reads of that variable

A write to a volatile variable

synchronizes-with

All subsequent reads of that variable


Man... I don't know what you just said, but you're special, man.
You reached out, and you touched a brother's heart.

The Empirical Approach

Thou Shalt Not Reinvent The Wheel

jcstress demo

Test Results (x86)

  • y: 0, x: 3
  • y: 0, x: 0
  • y: 1, x: 0
  • y: 1, x: 3

Test Results (ARM)

  • y: 0, x: 3
  • y: 0, x: 0
  • y: 1, x: 0
  • y: 1, x: 3

Test Results (x86, C1)

  • y: 0, x: 3
  • y: 0, x: 0
  • y: 1, x: 0
  • y: 1, x: 3

Where Did The Abstractions Leak To?

    void executedOnCpu0() {
        value = 10;
        finished = true;
    }

Nobody Wants To Be The Slow One

  • Each layer may apply some optimizations
  • Some optimizations may change the observed behaviour
  • Sometimes, it is perfectly acceptable
  • Some other times, it is not
  • The hardware engineers cannot know this in advance

For Instance: Cache Coherency

Variable Cached Value
finished false
value N/A
Variable Cached Value
finished N/A
value 0
value = 10;

  • — Invalidate this!
  • ...
  • ...
  • — Done!

finished = true;
  • Had to wait for a long time
  • The CPU was stalled
  • Optimization time!

value = 10;

(executed asynchronously)

finished = true;

(likewise)

Why We Need A Memory Model

Memory Barriers

void foo() {
    value = 10;
    magicUnicorn();
    finished = true;
}

void foo() {
    finished = true;
    magicUnicorn();
    value = 10;
}

(As seen by another thread)

The Two Types Of Memory Operations

Write
Read
Store
Load
ST
LD

They Should Not Be Treated Equally

For X, Y in [Store, Load]:

All X operations before an XY barrier

must complete before

Any Y operation after that barrier starts

Not Allowed

Allowed

Acquire And Release Semantice

The source of a synchronizes-with edge is called a release, and the destination is called an acquire

vstore(a.f, 1)
\---(sync-with)--->
vread(a.f, 1)

(source)

javac

(bytecode)

Frontend

(HIR)

JIT Optimizer

(LIR)

Backend

(native code)

...

(???)

PROFIT!

LIVE DEMO TIME!

Useful References