boolean a = false, b = false; int x = -1, y = -1; void test(int execution) { var t1 = new Thread(() -> { sleep(1); a = true; y = b ? 0 : 1; }); var t2 = new Thread(() -> { sleep(1); b = true; x = a ? 0 : 1; }); startAll(t1, t2); joinAll(t1, t2); if (x == 1 && y == 1) throw new RuntimeException("Failed at execution number : " + execution); }
t1
true
a
b
false
1
y
t2
0
x
x == 0 && y == 1
x == 1 && y = 0
x == 0 && y == 0
x = 1 and y = 1
public static void main(String[] args) { for (var i = 0; i < 10_000; i++) new Test().test(i); }
Exception in thread "main" java.lang.RuntimeException: Failed at execution number : 880 at org.example.counter.Test.test(Test.java:25) at org.example.counter.Test.main(Test.java:30)
Declare a and b volatile
volatile boolean a, b;
This forces the JVM to synchronize the variable to and from shared memory
Volatile is lightweight and faster than locking
testAndSet
compareAndSwap
public class Counter { int value = 0; void increment() { disableInterruptions(); int localCounter = value; localCounter = localCounter + 1; value = localCounter; enableInterruptions(); } }
boolean lock = false; void increment() { while (lock) { // Busy Loop } lock = true; // Begin Critical Section int localCounter = value; System.out.println(threadName() + " reads counter as: " + localCounter); localCounter = localCounter + 1; value = localCounter; // End Critical Section lock = false; System.out.println(threadName() + " updated counter to: " + value); }
volatile boolean lock = false;
To ensure that when one threads modify lock the others see it
lock
while (lock) { // Busy Loop } // I can have a Context switch here ! lock = true;
void increment() { while (v.compareAndSet(false, true)) { // busyLoop } // Critical section // ... }
Atomically test and modify the value on sucess
while (lock.compareAndSet(false, true)) Thread.yield();
fn counter() -> i32 { let mut counter = 0; thread::scope(|s| { s.spawn(|| counter += 1); s.spawn(|| counter += 1); }); return counter }
error[E0499]: cannot borrow `counter` as mutable more than once at a time ... Etc..
The borrow checker protects me from data races!