2. Java Memory Model
Java Memory Model is the model that describes the
behavior of memory in Java program.
The main task of this model is to reply the question that
can distinguish the concrete definition of «read» in the
program.
3. Java Memory Model
In the case of single-threaded languages usually the memory
pattern is quite simple:
That is why the memory model is often understood as the
model of memory behavior pattern in multi-threaded
applications. But in some cases it is required also for judging
about the pattern of single-threaded applications.
int x = 10;
int b = x;
int c = b + x;
x = c — b;
c = b;
4. Java Memory Model
In order to develop a multi-threaded application we
need to understand:
●
In what order the actions are executed in the application;
●
How does the data sharing between threads?
5. Java Memory Model: Access atomicity
We would like to make every action at the field
atomic:
long value = 0;
value = -1; System.out.println(value);
// 0, -1,
// 0xFFFFFFFF00000000 | 18446744069414584000
6. Java Memory Model: Access atomicity
In order to provide atomicity, we need to have this
support from hardware.
Possible problems:
– The absence of hardware operations for read/record of big values;
– The request to memory’s sub-system, for example, at х86 you can’t
place the data point at crossing of cashlines.
7. Java Memory Model: Access atomicity
In the current version of JMM we can see that the
work with all primitives except long/double has to
be atomic by default. For the activation of atomicity
of long/double it is required to use volatile.
8. Java Memory Model: Word tearing
We would like to make all operations at fields/array
elements/etc. to be independent:
int[] array = new int[4]; array[0] = 1; array[1] = 1;
array[0] = 2; array[1] = 2;
int a1 = array[0];
int a2 = array[1];
System.out.println(a1 == a2);
<term> <term> <join both>
9. Java Memory Model: Word tearing
To provide the independent read/record, unexpectedly we
need to have the same kind of support from hardware.
Possible problems:
– The absence of hardware operations for read/record of too small
data points. Usually this is for N < 8 bit.
Solution:
– The minimal data type has to be N >= 8 bit and then we can make
independent read/record for all types of data.
10. Java Memory Model: Word tearing
We wonder what will happen in such a case?
BitSet bitSet = new BitSet();
bitSet.set(1); bitSet.set(2);
boolean b1 = bitSet.get(1);
boolean b2 = bitSet.get(2);
System.out.println(b1 == b2);
<term> <term> <join both>
11. Java Memory Model: Reordering
We would like all actions in the program to be executed in the
same order as the one written by a programmer in the initial
code. But some types of optimization require certain changes:
int x = 0; int y = 0;
x = 10;
println(y);
y = 20;
println(x);
println(20); println(10);
...
12. Java Memory Model: Reordering
int x = 0; int y = 0;
int v1 = x;
int v2 = y;
y = 20;
x = 10;
int v2 = y;
int v1 = x;
y = 20;
x = 10;
int x = 0; int y = 0;
Runtime and iron don’t have the All-Seeing Eye to find what
changes never break the logics globally, they can define
correctness only of the local order — Program Order.
13. Java Memory Model: Synchronization Actions
JMM allows multiple types of optimization with appliance of
shifts and offers the set of SA for limiting this:
●
volatile read/write
●
lock/unlock monitor
●
first/last action in the thread
●
the action that launches the thread
●
the action that finds the interrupted thread (Thread.join().
Thread.isInterrupted(),etc.)
14. Java Memory Model: Synchronization Actions
JMM forbids to change the work order with SA. That’s why we
can say for sure in what order the actions at SA elements
happen in this example:
volatile int x = 0; volatile int y = 0;
y = 5;
println(x);
x = 5;
println(y);
15. Java Memory Model: Synchronization Actions
volatile int x = 0; volatile int y = 0;
y = 5;
println(x);
x = 5;
println(y);
Also SA elements help to connect the sequences of actions
between different threads, in such way forming
Synchronization Order:
16. Java Memory Model: Happens Before
But let’s examine the case, when we have actions not only at
SA elements, what will happen with x?
int x = 0; volatile int y = 0;
int v1 = y;
int v2 = x;
x = 5;
y = 5;
17. Java Memory Model: Happens Before
Right now let’s examine the case, when reading of v1 have
identified 5 in y, then Happens Before works in such way,
when v2 equals 5:
int x = 0; volatile int y = 0;
int v1 = y;
int v2 = x;
x = 5;
y = 5;
18. Java Memory Model: Happens Before
Right now let’s examine the case when v1 read in y - 0, in this
case v2 can be equal whether 0 or 5:
int x = 0; volatile int y = 0;
int v1 = y;
int v2 = x;
x = 5;
y = 5;
19. Java Memory Model: Happens Before
Now focus on another case:
volatile int a = 0; int b, c, d, e;
b = 1;
c = 2;
a = 5;
d = 3;
e = 4;
int v1 = d;
int v2 = e;
int v3 = a;
int v4 = b;
int v5 = c;
20. Java Memory Model: Happens Before
Let’s take a closer look at one more case:
volatile int a = 0, b; int c, d, e, g;
c = 1;
d = 2;
a = 3;
int v1 = b;
int v2 = e;
int v3 = g;
e = 4;
g = 5;
b = 6;
int v1 = a;
int v2 = c;
int v3 = d;
21. Java Memory Model: Happens Before
public class С<T> {
private T val;
public synchronized void setVal(final T val) {
if(this.val == null) this.val = val;
}
public synchronized T getVal() {
return val;
}
}
22. Java Memory Model: Happens Before
public class С<T> {
private T val;
public synchronized void setVal(final T val) {
if(this.val == null) this.val = val;
}
public T getVal() {
return val;
}
}
23. Java Memory Model: Happens Before
public class С<T> {
static volatile int BARRIER; int sink;
private T val;
public synchronized void setVal(final T val) {
if(this.val == null) this.val = val;
}
public T getVal() {
sink = BARRIER;
return val;
}
}
24. Java Memory Model: Happens Before
public class С<T> {
private volatile T val;
public synchronized void setVal(final T val) {
if(this.val == null) this.val = val;
}
public T getVal() {
return val;
}
}
25. Java Memory Model: Happens Before
public class C<T> {
private T val;
public synchronized void setVal(final T val) {
if(val == null) {
VarHandle.releaseFence();
this.val = val;
VarHandle.fullFence();
}
}
public T getVal() {
T val = this.val;
VarHandle.acquireFence();
return val;
}
}