PV168

Memory Model


Retrospective


Monitor


Monitor


Monitor

class Counter {
    private int value = 0;
    public synchronized int getValue() {
        return value++;
    }

    public int getSameValue() {
        synchronized(this) {
            return value++;
        }
    }
}

Atomic numbers


Atomic numbers

class Counter {
    private AtomicInteger value = new AtomicInteger(0);
    public int getValue() {
        return value.getAndIncrement();
    }
}

But how monitors and atomics work?


Memory Model

In computing, a memory model describes the interactions of threads through memory and their shared use of the data.[1]


Memory Model


Sequential Consistency

Compilers are allowed to reorder the instructions, when this does not affect the execution of the thread in isolation. [2]


Sequential Consistency

A = B = 0

// thread 1
r2 = A;
B = 1

// thread 2
r1 = B;
A = 2;

Synchronization Points


Actions


Shared variables


Happens-before


volatile


volatile

class VolatileExample {
    int x = 0;
    volatile boolean flag = false;
    public void writer() {
        x = 42;
        flag = true;
    }

    public void reader() {
        if (flag == true) {
          System.out.println(x); // guaranteed to see 42.
        }
    }
}

Atomic classes


Atomic classes

class AtomicExample {
    private int value = 0;
    private AtomicBoolean flag = new AtomicBoolean(false);
    public void writer() {
        value = 42;
        flag.set(true);
    }

    public void reader() {
        while (!flag.get()) {} // busy wait here
        System.out.println(value); // guaranteed to see 42.
    }
}

synchronized

public synchronized void doSomething() { /* ... */ }
public void doSomethingElse() {
    synchronized(this.attribute) {/* ... */}
}

Threads


Threads

class ThreadExample {
    public void run() {
        Integer value = 42;
        var t = new Thread(() -> value *= 2 );
        // value is 42
        t.start();
        t.join();
        // value is guaranteed to be 84;
    }
}

final Fields


Double-Checked Locking

Is this correct?

class Foo {
    private Helper helper = null;
    public Helper getHelper() {
        if (helper == null) {
            synchronized(this) {
                if (helper == null)
                    helper = new Helper();
            }
        }
        return helper;
    }
}

Double-Checked Locking Is Broken

And there is no way how it can be fixed.


How To Test The Correct Usage?


Without correct synchronization, very strange, confusing and counterintuitive behaviors are possible.