Dmitry Degrave, 2018 1
* Java Memory Model
Practical
Intro to JMM*
:
“There are only two hard things in
Computer Science: cache invalidation
and naming things” -- Phil Karlton
a journey
from Java to Asm
and Back Again
Image is the original artwork by J.R.R.Tolkien for the first edition, 1937
Dmitry Degrave, 2018 2
- OoOE
- Visibility
- volatile impl: Hotspot, C1
- volatile vs synchronized
- (Un)safe publications
- Final fields & Safe Initialization
- 4 Lazy Singleton Factories
- Atomicity
- References
Agenda
“There are only two hard things in
Computer Science: cache invalidation
and naming things” -- Phil Karlton
Image is the original artwork by J.R.R.Tolkien for the first edition, 1937
Dmitry Degrave, 2018 3
Motivation example
Thread 1 Thread 2
x = a;
b = 1;
y = b;
a = 1;
(x,y)==(0,0) ?
(x,y)==(0,1) ?
(x,y)==(1,0) ?
(x,y)==(1,1) ?
a = 0; b = 0;
(x,y) == (?,?)
Dmitry Degrave, 2018 4
Motivation example
Thread 1 Thread 2
x = a;
b = 1;
a = 1;
y = b;
Out of Order execution
a = 0; b = 0;
(x,y) == (?,?)
(x,y)==(0,0)
(x,y)==(0,1)
(x,y)==(1,0)
(x,y)==(1,1)
Dmitry Degrave, 2018 5
Runtime
(hardware & compilers)
under no obligation to
follow program order as
long as it does not modify
outcome of a program.
Single-threaded program.
details: https://en.wikipedia.org/wiki/Consistency_model
50th Anniversary Edition, J.R.R Tolkien, George Allen and Unwin, 1987
The sun is painted red as originally intended by Tolkien, but not allowed by budget for 1937 ed.
Dmitry Degrave, 2018 6
https://ourworldindata.org/wp-content/uploads/
2013/05/Transistor-Count-over-time.png
AMD
RISC Superscalar pipeline
https://en.wikipedia.org/wiki/File:
Superscalarpipeline.svg
Dmitry Degrave, 2018 7
Bytecode Machine code
reorder
Compiler/
JIT
Hardware
MM
Execution order
reorder*
*Doesn’t have to be actual OoOE, it’s memory effects that matter
strong->weak
PC/TSO/PSO/RMO/RC
Dmitry Degrave, 2018 8
x = a;
synchronized (this) {
y = b;
}
z = c;
Roach Motel
Dmitry Degrave, 2018 9
x = a;
synchronized (this) {
y = b;
}
z = c;
Roach Motel
Dmitry Degrave, 2018 10
x = a;
v = b;
z = c;
x = a;
y = v;
z = c;
Volatile semantics
v - volatile
Dmitry Degrave, 2018
Visibility
Dmitry Degrave, 2018 12
Another motivation example
x == 1 ?
x == 0 ?
a = 0; b = true; x == ?
Thread 1 Thread 2
a = 1;
if (a == 1)
b = false;
while (b);
b = false;
if (!b) x = a;
Dmitry Degrave, 2018 13
What does that mean
operation is finished ?
• result of operation is in RAM
• next instruction started execution
• result is visible in point of usage
• something else
Dmitry Degrave, 2018 14
• result of operation is in RAM
• next instruction started execution
• result is visible in point of usage
• something else
What does that mean
operation is finished ?
Dmitry Degrave, 2018
https://en.wikipedia.org/wiki/File:Hwloc.png
Dmitry Degrave, 2018 16
Another motivation example
x == 1
x == 0
a = 0; b = true; x == ?
Thread 1 Thread 2
a = 1;
if (a == 1)
b = false;
while (b);
b = false;
if (!b) x = a;
Dmitry Degrave, 2018 17
https://docs.oracle.com/javase/specs
Original artwork by J.R.R.Tolkien for the first edition, 1937
Dmitry Degrave, 2018 18
Happens-before between threads
...
write
...
unlock
...
lock
...
read
...
...
Everything before the unlock...
...is visible to
everything after
the lock on the
same monitor in
any thread
Dmitry Degrave, 2018 19
Happens-before between threads
...
write
...
write(V)
...
read(V)
...
read
...
...
Everything before the
volatile write...
...is visible to
everything after
volatile read on
the same variable
in any thread
Dmitry Degrave, 2018 20
class A {
int a, x, y;
int b;
public void t1() {
x = a;
b = 1;
}
public void t2() {
y = b;
a = 1;
}
}
“Talk is cheap…
...show me the code” -- Linus
Image is the artwork for first Canadian paperback edition, Methuen Publications, First Printing, 1977
Dmitry Degrave, 2018 21
x = a
lir_membar_release
b = 1
lir_membar
IR*
y = b
lir_membar_acquire
a = 1
x86 / SPARC TSO
membar(StoreLoad)
-> lock / membar
no-op
no-op
* Low-Level Intermediate Representation in Hotspot
class A {
int a, x, y;
volatile int b;
public void t1() {
x = a;
b = 1;
}
public void t2() {
y = b;
a = 1;
}
}
Dmitry Degrave, 2018 22
x = a
lir_membar_release
b = 1
lir_membar
IR*
y = b
lir_membar_acquire
a = 1
PowerPC
fence -> sync ->
sync(0)
release -> lwsync()
-> sync(1)
acquire -> lwsync()
-> sync(1)
* Low-Level Intermediate Representation in Hotspot
class A {
int a, x, y;
volatile int b;
public void t1() {
x = a;
b = 1;
}
public void t2() {
y = b;
a = 1;
}
}
Dmitry Degrave, 2018 23
x = a
lir_membar_release
b = 1
lir_membar
IR*
Store Memory Barrier
Store Buffers flushed
to Cache
y = b
lir_membar_acquire
a = 1
Load Memory Barrier
Invalidate Queue
Invalidated
CPU
* Low-Level Intermediate Representation in Hotspot
class A {
int a, x, y;
volatile int b;
public void t1() {
x = a;
b = 1;
}
public void t2() {
y = b;
a = 1;
}
}
Dmitry Degrave, 2018 24
Happens-before between threads Recap
...
write
...
write(V)
...
read(V)
...
read
...
...
Everything before the
volatile write...
...is visible to
everything after
volatile read on
the same variable
in any thread
Dmitry Degrave, 2018 25
A journey from Java to
Asm and Back Again:
Volatile
vs
Synchronized
Image is the artwork for 75th Anniversary Edition, published by Houghton Mifflin Harcourt, 2012
Dmitry Degrave, 2018 26
public class Counter {
private volatile int counter;
public int getCounter() {
return counter;
}
public int increment() {
return counter++;
}
}
After
10 000 calls,
counter == ?
Dmitry Degrave, 2018 27
public class Counter {
private volatile int counter;
public int getCounter() {
return counter;
}
public synchronized int increment() {
return counter++; // counter++ is not atomic !
}
}
“Cheap Read-Write Lock” pattern
Readers
never block
Writers & vice
versa!
Dmitry Degrave, 2018
● equal in terms of visibility
○ Lock and volatile read are similar in their "acquire" action
○ Unlock and volatile write are similar in their "release" action
● Interchangeable only if:
○ Writes to volatile variable do not depend on its current value
○ Variable does not participate in invariants with other variables
28
volatile vs synchronized
Dmitry Degrave, 2018
● Volatile variables:
○ usually faster than locks
○ cannot cause a deadlock
○ lock-free semantics
○ simplicity
29
volatile vs synchronized
Dmitry Degrave, 2018
● Volatile variables:
○ not sufficient to
implement MT-safe
counters, mutex, or
multi-variable invariants
○ don't have wait/notify
semantics 30
volatile vs synchronized
Dmitry Degrave, 2018 31
def: safe publication -
everything written before
publication is visible
after
(un)safe publication
Dmitry Degrave, 2018 32
class A {
int f;
A() {f = 42;}
}
Thread 1 Thread 2
a = new A(); if (a != null)
println(a.f);
A a;
What does it print ?
(un)safe publication: toy(*)
(*) Courtesy of Aleksey Shipilёv
Dmitry Degrave, 2018 33
class A {
int f;
A() {f = 42;}
}
Thread 1 Thread 2
a = new A(); if (a != null)
println(a.f);
A a;
(un)safe publication: toy(*)
(*) Courtesy of Aleksey Shipilёv
What does it print ? <nothing>, 0, 42, <throws NPE>
Dmitry Degrave, 2018 34
class A {
int f;
A() {f = 42;}
}
Thread 1 Thread 2
a = new A(); A ta = a;
if (ta != null)
println(ta.f);
A a;
(un)safe publication: toy(*)
(*) Courtesy of Aleksey Shipilёv
What does it print ? <nothing>, 0, 42
Dmitry Degrave, 2018 35
public class UnsafeLazyInitialization {
private static Resource resource;
public static Resource getInstance() {
if (resource == null)
resource = new Resource(); // unsafe publication
return resource;
}
}
(un)safe publication
"Java Concurrency In Practice", Brian Göetz et al.
Dmitry Degrave, 2018 36
public class SafeLazyInitialization {
private static Resource resource;
public synchronized static Resource getInstance() {
if (resource == null)
resource = new Resource(); // safe publication
return resource;
}
}
safe publication via synchronization
"Java Concurrency In Practice", Brian Göetz et al.
Dmitry Degrave, 2018 37
public class DoubleCheckedLocking {
private static Resource resource;
public static Resource getInstance() {
if (resource == null) {
synchronized (DoubleCheckedLocking.class) {
if (resource == null)
resource = new Resource(); // publish
}
}
return resource;
}
}
Double-checked Locking
"Java Concurrency In Practice", Brian Göetz et al.
Dmitry Degrave, 2018 38
public class DoubleCheckedLocking {
private static volatile Resource resource;
public static Resource getInstance() {
if (resource == null) {
synchronized (DoubleCheckedLocking.class) {
if (resource == null)
resource = new Resource(); // publish
}
}
return resource;
}
}
Double-checked Locking, fixed
"Java Concurrency In Practice", Brian Göetz et al.
Dmitry Degrave, 2018 39
public class DoubleCheckedLocking {
private static volatile Resource[] resource;
public static Resource[] getInstance() {
if (resource == null)
synchronized (DoubleCheckedLocking.class) {
if (resource == null) {
resource = new Resource[42];
resource[0] = new Resource();
……………………………………………………………….…...
}
}
return resource;
}
}
DCL: is it still Ok ?
Dmitry Degrave, 2018 40
public class DoubleCheckedLocking {
private static volatile List<Resource> resource;
public static List<Resource> getInstance() {
if (resource == null)
synchronized (DoubleCheckedLocking.class) {
if (resource == null) {
resource = new LinkedList<Resource>();
resource.add(new Resource());
……………………………………………………………….…...
}
}
return resource;
}
}
DCL: and this ?
Dmitry Degrave, 2018 41
DCL: what about this ?
public class DoubleCheckedLocking {
private static volatile Resource resource;
public static Resource getInstance() {
Resource res = resource; // single volatile read
if (res == null) {
synchronized (DoubleCheckedLocking.class) {
if (resource == null) {
resource = new Resource();
}
res = resource;
}
}
return res; // non-volatile local read, a tiny bit better performance
}
}
Dmitry Degrave, 2018 42
public class ResourceFactory {
private static class ResourceHolder {
public static Resource resource = new Resource();
}
public static Resource getResource() {
return ResourceHolder.resource;
}
}
safe publication: Holder idiom & static initializer
"Java Concurrency In Practice", Brian Göetz et al.
Dmitry Degrave, 2018 43
public class MonoBean {
private T val;
public synchronized void setVal(T val) {
this.val = val;
}
public T getVal() {
return val;
}
}
setter + getter
Dmitry Degrave, 2018 44
public class MonoBean {
private T val;
public synchronized void setVal(T val) {
this.val = val;
}
public synchronized T getVal() {
return val;
}
}
setter + getter
Dmitry Degrave, 2018 45
public class MonoBean {
private volatile T val;
public void setVal(T val) {
this.val = val;
}
public T getVal() {
return val;
}
}
setter + getter
Dmitry Degrave, 2018
Final fields &
Safe
Initialization
Dmitry Degrave, 2018 47
● There is a synthetic freeze action at the
end of constructor, which "freezes" the
state of the final fields
● All threads see correct values of final
fields set by C'r
Final fields semantics
● Holds true for all dereference-chain: any field of any object
reachable through a final field is seen correctly by any
thread (in its “initial” state as it was constructed)
class A {
final int f;
A() {f = 42;}
}
freeze
Dmitry Degrave, 2018 48
● Immune to unsafe publications / races !
(if reference is visible through them)
● Reference to object should not escape C'r
before "freeze", otherwise no guarantees
provided
● Implemented as [LoadStore|StoreStore]
in Hotspot -> a single final field provides
final's visibility semantics to all class fields!
Final fields semantics
class A {
final int f;
A() {f = 42;}
}
freeze
Dmitry Degrave, 2018 49
Thread 1 Thread 2
a = new A(); A ta = a;
if (ta != null)
println(ta.f);
A a;
What does it print ? <nothing>, 42
safe initialization
freeze
Unsafe publication
class A {
final int f;
A() {f = 42;}
}
Dmitry Degrave, 2018 50
public class DCL {
private static volatile Resource resource;
public static Resource getInstance() {
if (resource == null) {
synchronized (DCL.class) {
if (resource == null)
resource = new Resource();
}
}
return resource;
}
}
Recap: DCL
Volatile -> final
Dmitry Degrave, 2018 51
Unsafe publication + safe initialization: 1st try
private static class R {
final T instance;
R(T t) {
this.instance = t;
}
}
} // UnsafeDCL
public class UnsafeDCL {
private static R resource;
public static T getInstance() {
if (resource == null) {
synchronized (UnsafeDCL.class) {
if (resource == null)
resource = new R(new T());
}
}
return resource.instance;
}
What’s wrong ?
Dmitry Degrave, 2018 52
public class UnsafeDCL {
private static R resource;
public static T getInstance() {
if (resource == null) { // race
synchronized (UnsafeDCL.class) {
if (resource == null)
resource = new R(new T());
}
}
return resource.instance; // race
}
Unsafe publication + safe initialization: 1st try
private static class R {
final T instance;
R(T t) {
this.instance = t;
}
}
} // UnsafeDCL
2 reads
is too much !!
2nd can be null
Dmitry Degrave, 2018 53
public class DCLWFinal {
private static R resource;
public static T getInstance() {
R res = resource; // race
if (res == null) {
synchronized (DCLWFinal.class) {
if (resource == null) {
resource = new R(new T());
}
res = resource;
}
}
return res.instance; // no race
}
private static class R {
final T instance;
R(T t) {
this.instance = t;
}
}
} // DCLWFinal
Now it’s fine
Dmitry Degrave, 2018
4 Lazy
Singleton
Factories
Dmitry Degrave, 2018 55
Have already seen implementation
through:
1. Volatile field - DCL
2. Static field - Holder idiom
3. Final field - DCL w/ Local +
wrapper w/ final
4. Synchronized access to field
4 Lazy Singleton Factories
class B {
private A a;
public synchronized A get() {
if (a == null) {
a = new A();
}
return a;
}
}
Dmitry Degrave, 2018
Atomicity
Dmitry Degrave, 2018
JMM guarantees:
● reads and writes are atomic for
all built-in types, except long
and double
● volatile long and volatile double
are atomic
57
Atomicity
Dmitry Degrave, 2018
References
Dmitry Degrave, 2018 59
“Java Memory Model Pragmatics” by Aleksey Shipilёv
JMM fundamentals: Access atomicity, word tearing,
Sequential Consistency, Synchronization Order, SO-PO/SO
consistencies, Synchronizes-With Order, Happens-Before,
Sequential Consistency - Data Race Free, "Roach Motel", Out
of Thin Air values, Finals semantics, JMM9.
https://shipilev.net/blog/2014/jmm-pragmatics/
Dmitry Degrave, 2018 60
“Close Encounters of The Java Memory Model Kind”
by Aleksey Shipilёv
JMM fundamentals follow up. Common misunderstandings,
mistakes and misconceptions.
https://shipilev.net/blog/2016/close-encounters-of-jmm-kind
Dmitry Degrave, 2018 61
“Safe Publication and Safe Initialization in Java”
by Aleksey Shipilёv
JMM in everyday life. Singletons. Safe Publications & Safe
Initializations. Performance and memory costs.
https://shipilev.net/blog/2014/safe-public-construction/
Dmitry Degrave, 2018
Thanks to:
✗ SlidesWare by Google Slides
✗ Template by SlidesCarnival
http://www.slidescarnival.com
62
Credits

Practical Introduction to Java Memory Model

  • 1.
    Dmitry Degrave, 20181 * Java Memory Model Practical Intro to JMM* : “There are only two hard things in Computer Science: cache invalidation and naming things” -- Phil Karlton a journey from Java to Asm and Back Again Image is the original artwork by J.R.R.Tolkien for the first edition, 1937
  • 2.
    Dmitry Degrave, 20182 - OoOE - Visibility - volatile impl: Hotspot, C1 - volatile vs synchronized - (Un)safe publications - Final fields & Safe Initialization - 4 Lazy Singleton Factories - Atomicity - References Agenda “There are only two hard things in Computer Science: cache invalidation and naming things” -- Phil Karlton Image is the original artwork by J.R.R.Tolkien for the first edition, 1937
  • 3.
    Dmitry Degrave, 20183 Motivation example Thread 1 Thread 2 x = a; b = 1; y = b; a = 1; (x,y)==(0,0) ? (x,y)==(0,1) ? (x,y)==(1,0) ? (x,y)==(1,1) ? a = 0; b = 0; (x,y) == (?,?)
  • 4.
    Dmitry Degrave, 20184 Motivation example Thread 1 Thread 2 x = a; b = 1; a = 1; y = b; Out of Order execution a = 0; b = 0; (x,y) == (?,?) (x,y)==(0,0) (x,y)==(0,1) (x,y)==(1,0) (x,y)==(1,1)
  • 5.
    Dmitry Degrave, 20185 Runtime (hardware & compilers) under no obligation to follow program order as long as it does not modify outcome of a program. Single-threaded program. details: https://en.wikipedia.org/wiki/Consistency_model 50th Anniversary Edition, J.R.R Tolkien, George Allen and Unwin, 1987 The sun is painted red as originally intended by Tolkien, but not allowed by budget for 1937 ed.
  • 6.
    Dmitry Degrave, 20186 https://ourworldindata.org/wp-content/uploads/ 2013/05/Transistor-Count-over-time.png AMD RISC Superscalar pipeline https://en.wikipedia.org/wiki/File: Superscalarpipeline.svg
  • 7.
    Dmitry Degrave, 20187 Bytecode Machine code reorder Compiler/ JIT Hardware MM Execution order reorder* *Doesn’t have to be actual OoOE, it’s memory effects that matter strong->weak PC/TSO/PSO/RMO/RC
  • 8.
    Dmitry Degrave, 20188 x = a; synchronized (this) { y = b; } z = c; Roach Motel
  • 9.
    Dmitry Degrave, 20189 x = a; synchronized (this) { y = b; } z = c; Roach Motel
  • 10.
    Dmitry Degrave, 201810 x = a; v = b; z = c; x = a; y = v; z = c; Volatile semantics v - volatile
  • 11.
  • 12.
    Dmitry Degrave, 201812 Another motivation example x == 1 ? x == 0 ? a = 0; b = true; x == ? Thread 1 Thread 2 a = 1; if (a == 1) b = false; while (b); b = false; if (!b) x = a;
  • 13.
    Dmitry Degrave, 201813 What does that mean operation is finished ? • result of operation is in RAM • next instruction started execution • result is visible in point of usage • something else
  • 14.
    Dmitry Degrave, 201814 • result of operation is in RAM • next instruction started execution • result is visible in point of usage • something else What does that mean operation is finished ?
  • 15.
  • 16.
    Dmitry Degrave, 201816 Another motivation example x == 1 x == 0 a = 0; b = true; x == ? Thread 1 Thread 2 a = 1; if (a == 1) b = false; while (b); b = false; if (!b) x = a;
  • 17.
    Dmitry Degrave, 201817 https://docs.oracle.com/javase/specs Original artwork by J.R.R.Tolkien for the first edition, 1937
  • 18.
    Dmitry Degrave, 201818 Happens-before between threads ... write ... unlock ... lock ... read ... ... Everything before the unlock... ...is visible to everything after the lock on the same monitor in any thread
  • 19.
    Dmitry Degrave, 201819 Happens-before between threads ... write ... write(V) ... read(V) ... read ... ... Everything before the volatile write... ...is visible to everything after volatile read on the same variable in any thread
  • 20.
    Dmitry Degrave, 201820 class A { int a, x, y; int b; public void t1() { x = a; b = 1; } public void t2() { y = b; a = 1; } } “Talk is cheap… ...show me the code” -- Linus Image is the artwork for first Canadian paperback edition, Methuen Publications, First Printing, 1977
  • 21.
    Dmitry Degrave, 201821 x = a lir_membar_release b = 1 lir_membar IR* y = b lir_membar_acquire a = 1 x86 / SPARC TSO membar(StoreLoad) -> lock / membar no-op no-op * Low-Level Intermediate Representation in Hotspot class A { int a, x, y; volatile int b; public void t1() { x = a; b = 1; } public void t2() { y = b; a = 1; } }
  • 22.
    Dmitry Degrave, 201822 x = a lir_membar_release b = 1 lir_membar IR* y = b lir_membar_acquire a = 1 PowerPC fence -> sync -> sync(0) release -> lwsync() -> sync(1) acquire -> lwsync() -> sync(1) * Low-Level Intermediate Representation in Hotspot class A { int a, x, y; volatile int b; public void t1() { x = a; b = 1; } public void t2() { y = b; a = 1; } }
  • 23.
    Dmitry Degrave, 201823 x = a lir_membar_release b = 1 lir_membar IR* Store Memory Barrier Store Buffers flushed to Cache y = b lir_membar_acquire a = 1 Load Memory Barrier Invalidate Queue Invalidated CPU * Low-Level Intermediate Representation in Hotspot class A { int a, x, y; volatile int b; public void t1() { x = a; b = 1; } public void t2() { y = b; a = 1; } }
  • 24.
    Dmitry Degrave, 201824 Happens-before between threads Recap ... write ... write(V) ... read(V) ... read ... ... Everything before the volatile write... ...is visible to everything after volatile read on the same variable in any thread
  • 25.
    Dmitry Degrave, 201825 A journey from Java to Asm and Back Again: Volatile vs Synchronized Image is the artwork for 75th Anniversary Edition, published by Houghton Mifflin Harcourt, 2012
  • 26.
    Dmitry Degrave, 201826 public class Counter { private volatile int counter; public int getCounter() { return counter; } public int increment() { return counter++; } } After 10 000 calls, counter == ?
  • 27.
    Dmitry Degrave, 201827 public class Counter { private volatile int counter; public int getCounter() { return counter; } public synchronized int increment() { return counter++; // counter++ is not atomic ! } } “Cheap Read-Write Lock” pattern Readers never block Writers & vice versa!
  • 28.
    Dmitry Degrave, 2018 ●equal in terms of visibility ○ Lock and volatile read are similar in their "acquire" action ○ Unlock and volatile write are similar in their "release" action ● Interchangeable only if: ○ Writes to volatile variable do not depend on its current value ○ Variable does not participate in invariants with other variables 28 volatile vs synchronized
  • 29.
    Dmitry Degrave, 2018 ●Volatile variables: ○ usually faster than locks ○ cannot cause a deadlock ○ lock-free semantics ○ simplicity 29 volatile vs synchronized
  • 30.
    Dmitry Degrave, 2018 ●Volatile variables: ○ not sufficient to implement MT-safe counters, mutex, or multi-variable invariants ○ don't have wait/notify semantics 30 volatile vs synchronized
  • 31.
    Dmitry Degrave, 201831 def: safe publication - everything written before publication is visible after (un)safe publication
  • 32.
    Dmitry Degrave, 201832 class A { int f; A() {f = 42;} } Thread 1 Thread 2 a = new A(); if (a != null) println(a.f); A a; What does it print ? (un)safe publication: toy(*) (*) Courtesy of Aleksey Shipilёv
  • 33.
    Dmitry Degrave, 201833 class A { int f; A() {f = 42;} } Thread 1 Thread 2 a = new A(); if (a != null) println(a.f); A a; (un)safe publication: toy(*) (*) Courtesy of Aleksey Shipilёv What does it print ? <nothing>, 0, 42, <throws NPE>
  • 34.
    Dmitry Degrave, 201834 class A { int f; A() {f = 42;} } Thread 1 Thread 2 a = new A(); A ta = a; if (ta != null) println(ta.f); A a; (un)safe publication: toy(*) (*) Courtesy of Aleksey Shipilёv What does it print ? <nothing>, 0, 42
  • 35.
    Dmitry Degrave, 201835 public class UnsafeLazyInitialization { private static Resource resource; public static Resource getInstance() { if (resource == null) resource = new Resource(); // unsafe publication return resource; } } (un)safe publication "Java Concurrency In Practice", Brian Göetz et al.
  • 36.
    Dmitry Degrave, 201836 public class SafeLazyInitialization { private static Resource resource; public synchronized static Resource getInstance() { if (resource == null) resource = new Resource(); // safe publication return resource; } } safe publication via synchronization "Java Concurrency In Practice", Brian Göetz et al.
  • 37.
    Dmitry Degrave, 201837 public class DoubleCheckedLocking { private static Resource resource; public static Resource getInstance() { if (resource == null) { synchronized (DoubleCheckedLocking.class) { if (resource == null) resource = new Resource(); // publish } } return resource; } } Double-checked Locking "Java Concurrency In Practice", Brian Göetz et al.
  • 38.
    Dmitry Degrave, 201838 public class DoubleCheckedLocking { private static volatile Resource resource; public static Resource getInstance() { if (resource == null) { synchronized (DoubleCheckedLocking.class) { if (resource == null) resource = new Resource(); // publish } } return resource; } } Double-checked Locking, fixed "Java Concurrency In Practice", Brian Göetz et al.
  • 39.
    Dmitry Degrave, 201839 public class DoubleCheckedLocking { private static volatile Resource[] resource; public static Resource[] getInstance() { if (resource == null) synchronized (DoubleCheckedLocking.class) { if (resource == null) { resource = new Resource[42]; resource[0] = new Resource(); ……………………………………………………………….…... } } return resource; } } DCL: is it still Ok ?
  • 40.
    Dmitry Degrave, 201840 public class DoubleCheckedLocking { private static volatile List<Resource> resource; public static List<Resource> getInstance() { if (resource == null) synchronized (DoubleCheckedLocking.class) { if (resource == null) { resource = new LinkedList<Resource>(); resource.add(new Resource()); ……………………………………………………………….…... } } return resource; } } DCL: and this ?
  • 41.
    Dmitry Degrave, 201841 DCL: what about this ? public class DoubleCheckedLocking { private static volatile Resource resource; public static Resource getInstance() { Resource res = resource; // single volatile read if (res == null) { synchronized (DoubleCheckedLocking.class) { if (resource == null) { resource = new Resource(); } res = resource; } } return res; // non-volatile local read, a tiny bit better performance } }
  • 42.
    Dmitry Degrave, 201842 public class ResourceFactory { private static class ResourceHolder { public static Resource resource = new Resource(); } public static Resource getResource() { return ResourceHolder.resource; } } safe publication: Holder idiom & static initializer "Java Concurrency In Practice", Brian Göetz et al.
  • 43.
    Dmitry Degrave, 201843 public class MonoBean { private T val; public synchronized void setVal(T val) { this.val = val; } public T getVal() { return val; } } setter + getter
  • 44.
    Dmitry Degrave, 201844 public class MonoBean { private T val; public synchronized void setVal(T val) { this.val = val; } public synchronized T getVal() { return val; } } setter + getter
  • 45.
    Dmitry Degrave, 201845 public class MonoBean { private volatile T val; public void setVal(T val) { this.val = val; } public T getVal() { return val; } } setter + getter
  • 46.
    Dmitry Degrave, 2018 Finalfields & Safe Initialization
  • 47.
    Dmitry Degrave, 201847 ● There is a synthetic freeze action at the end of constructor, which "freezes" the state of the final fields ● All threads see correct values of final fields set by C'r Final fields semantics ● Holds true for all dereference-chain: any field of any object reachable through a final field is seen correctly by any thread (in its “initial” state as it was constructed) class A { final int f; A() {f = 42;} } freeze
  • 48.
    Dmitry Degrave, 201848 ● Immune to unsafe publications / races ! (if reference is visible through them) ● Reference to object should not escape C'r before "freeze", otherwise no guarantees provided ● Implemented as [LoadStore|StoreStore] in Hotspot -> a single final field provides final's visibility semantics to all class fields! Final fields semantics class A { final int f; A() {f = 42;} } freeze
  • 49.
    Dmitry Degrave, 201849 Thread 1 Thread 2 a = new A(); A ta = a; if (ta != null) println(ta.f); A a; What does it print ? <nothing>, 42 safe initialization freeze Unsafe publication class A { final int f; A() {f = 42;} }
  • 50.
    Dmitry Degrave, 201850 public class DCL { private static volatile Resource resource; public static Resource getInstance() { if (resource == null) { synchronized (DCL.class) { if (resource == null) resource = new Resource(); } } return resource; } } Recap: DCL Volatile -> final
  • 51.
    Dmitry Degrave, 201851 Unsafe publication + safe initialization: 1st try private static class R { final T instance; R(T t) { this.instance = t; } } } // UnsafeDCL public class UnsafeDCL { private static R resource; public static T getInstance() { if (resource == null) { synchronized (UnsafeDCL.class) { if (resource == null) resource = new R(new T()); } } return resource.instance; } What’s wrong ?
  • 52.
    Dmitry Degrave, 201852 public class UnsafeDCL { private static R resource; public static T getInstance() { if (resource == null) { // race synchronized (UnsafeDCL.class) { if (resource == null) resource = new R(new T()); } } return resource.instance; // race } Unsafe publication + safe initialization: 1st try private static class R { final T instance; R(T t) { this.instance = t; } } } // UnsafeDCL 2 reads is too much !! 2nd can be null
  • 53.
    Dmitry Degrave, 201853 public class DCLWFinal { private static R resource; public static T getInstance() { R res = resource; // race if (res == null) { synchronized (DCLWFinal.class) { if (resource == null) { resource = new R(new T()); } res = resource; } } return res.instance; // no race } private static class R { final T instance; R(T t) { this.instance = t; } } } // DCLWFinal Now it’s fine
  • 54.
    Dmitry Degrave, 2018 4Lazy Singleton Factories
  • 55.
    Dmitry Degrave, 201855 Have already seen implementation through: 1. Volatile field - DCL 2. Static field - Holder idiom 3. Final field - DCL w/ Local + wrapper w/ final 4. Synchronized access to field 4 Lazy Singleton Factories class B { private A a; public synchronized A get() { if (a == null) { a = new A(); } return a; } }
  • 56.
  • 57.
    Dmitry Degrave, 2018 JMMguarantees: ● reads and writes are atomic for all built-in types, except long and double ● volatile long and volatile double are atomic 57 Atomicity
  • 58.
  • 59.
    Dmitry Degrave, 201859 “Java Memory Model Pragmatics” by Aleksey Shipilёv JMM fundamentals: Access atomicity, word tearing, Sequential Consistency, Synchronization Order, SO-PO/SO consistencies, Synchronizes-With Order, Happens-Before, Sequential Consistency - Data Race Free, "Roach Motel", Out of Thin Air values, Finals semantics, JMM9. https://shipilev.net/blog/2014/jmm-pragmatics/
  • 60.
    Dmitry Degrave, 201860 “Close Encounters of The Java Memory Model Kind” by Aleksey Shipilёv JMM fundamentals follow up. Common misunderstandings, mistakes and misconceptions. https://shipilev.net/blog/2016/close-encounters-of-jmm-kind
  • 61.
    Dmitry Degrave, 201861 “Safe Publication and Safe Initialization in Java” by Aleksey Shipilёv JMM in everyday life. Singletons. Safe Publications & Safe Initializations. Performance and memory costs. https://shipilev.net/blog/2014/safe-public-construction/
  • 62.
    Dmitry Degrave, 2018 Thanksto: ✗ SlidesWare by Google Slides ✗ Template by SlidesCarnival http://www.slidescarnival.com 62 Credits