the java memory model - ulm · java memory model •minimal guarantees the jvm must make about when...

39
The Java Memory Model What is it and why would I want one? Jörg Domaschka. ART Group, Institute for Distributed Systems Ulm University, Germany December 14, 2009

Upload: others

Post on 03-Oct-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

The Java Memory Model

What is it and why would I want one?

Jörg Domaschka. ART Group,

Institute for Distributed Systems

Ulm University, Germany December 14, 2009

Page 2: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

public class WhatDoIPrint{

static int x = 0, y = 0, a = 0, b = 0;

public static void main(String[] args){

Thread one = new Thread(new Runnable(){

public void run(){

a = 1;

x = b;

} )};

Thread other = new Thread(new Runnable(){

public void run(){

b = 1;

y = a;

} )};

one.start(); other.start();

one.join(); other.join();

System.out.println(„( “ + x + „, “ + y + „ )“);

}

Page 3: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Possible Results

• Obviously: (1,0), (1,1), (0,1)

• Surprisingly: (0,0)

Why that?

Code reordering

x = b (0)

b = 1 y = a (0)

a = 1reorder

Page 4: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Reorderings

Every entity optimises heavily

• Compiler

• Processor

• Caches

In our case

• No shared variables declared

• Optimise for local operation

Page 5: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Outline

• Motivation

• JMM in a Nutshell

• The final Keyword

• Conclusions

Page 6: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Definitions

Memory Model:

• Specifies when actions of one thread on memory are guaranteed to be visible by others.

• Defines:

– What you can expect from the system

– Operations for additional support

• Used in– Multi-core/cpu architecture

– Multi-level caching

Page 7: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Java Memory Model

• Minimal guarantees the JVM must make about when writes to variables become visible.

predictability and ease of programmingvs

high-performance

• What can we expect?

• Which additional operations do we have?

Page 8: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

What to Expect?

Sequential Consistency

• Mental model of many programmers

• A happy, if unrealistic model [Goetz]

• The von Neumann model is only a vague approximation [Goetz]

Page 9: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

What to Expect?

In the absence of special operations:

• Java provides barely any inter-thread guarantees

• Execution of a single thread is as-if sequential

Don‘t expect anything

• Unless you prepared for it

Page 10: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Special Operations?

• In JMM

– Threads execute actions

– Actions are partially ordered(happens-before: antisymmetric, reflexive, transitive)

– Default: actions of different threads are not ordered

Page 11: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Special Actions!

Inter-thread ordering actions

– Lock/unlock on monitor

– Volatile variables

– Thread start/termination/interruption

– ...

– Synchronize all caches with main memory(Piggybacking on synchronization is possible)

Define a synchronizes-with relation

Page 12: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Synchronisation Actions

• Totally ordered

– With respect to a single mutex/volatile variable

– No ordering guarantees for distinct variables

• Synchronized programmes

– Data race: Conflicting access to a shared variable that is not synchronized

– Correctly synchronized: All sequentially consistent executions are free of data races

Page 13: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Correct or Not?

Thread 1:

X = 1;

Lock M1;

Y = 1;

Unlock M1;

Thread 2:

Lock M1;

i = Y;

Unlock M1;

j = X;

Page 14: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Correct or Not?

Thread 1:

X = 1

Lock M1

Y = 1

Unlock M1

Lock M1

i = Y

Unlock M1

j = X

Thread 2:

Page 15: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Correct or Not?

Thread 1:

X = 1

Lock M1

Y = 1

Unlock M1

Lock M1

i = Y

Unlock M1

j = X

Thread 2:

Page 16: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Best Practices - Locking

Every shared, mutable variable

• Guarded by exactly one lock

Invariants that involve multiple variables

• All variables must be guarded by the same lock

• Resist the temptation to prematurely sacrifice simplicity for the sake of performance.

Page 17: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Best Pratices - volatile

Volatile variables can only guarantee visibility.

• Writes must not depend on current value

• Does not participate in invariants

• Locking is not required for other reasons

Page 18: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Outline

• Motivation

• JMM in a Nutshell

• The final Keyword

• Conclusions

Page 19: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

The final Keyword

Semantics of final Fields

• Initialised once

• Never changed under normal circumstances

Allows for compiler optimisations

• Do not depend on memory barriers (i.e., locks)

• Can always be cached

Benefit: thread-safe immutable objects

Page 20: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

final‘s Effect on Memory

• Freezing final fields

– At end of constructor

• But not before

– Reading a final field by constructing thread beforefreeze yields default value

• Allows building immutable objects

– Vital to Java security architecture

– Strings must not change

Page 21: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

final‘s Visibility Guarantees

• After freeze of Object o– All threads see correct value of final fields…

– … and fields exclusively reachable through them

– … if they obtained reference to o after the freeze

• Non-final fields– Only guaranteed to bee seen correctly by finalizer

– Unless synchronisation is used

Requires safe publication of objects

Page 22: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Example

class FinalFieldExample {

final int x;

int y;

static FinalFieldExample f;

public FinalFieldExample(){

x = 3;

y = 4;

}

static void reader(){

if (f != null){

int i = f.x;

int j = f.y;

}

}

static void writer(){

f = new FinalFieldExample();

}

}

Page 23: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Example - Publication

class UnsafeLazyInitialisation{

private static Resource resouce;

public static Resource getInstance(){

if(resource == null)

resource = new Resource();

return resource;

}

}

Page 24: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Example – Publication (II)

class SafeLazyInitialisation{

private static Resource resouce;

public synchronized static Resource getInstance(){

if(resource == null)

resource = new Resource();

return resource;

}

}

Page 25: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Example – Publication (III)

class EagerInitialisation{

private static Resource resouce = new Resource();

public synchronized static Resource getInstance(){

return resource;

}

}

Page 26: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Example – Publication (IV)

class ResourceFactory{

private static class ResourceHolder {

public static Resource resource = new Resource();

}

public synchronized static Resource getInstance(){return ResourceHolder.resource;

}

}

Page 27: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Example – Publication (V)

pulic Holder holder;

public void initialise(){

holder = new Holder(42);

}

public class Holder {

private int n;

public Holder(int i) {

n = i;

}

public void assertSanity(){

assert n == n : „This statement is false“;

}

}

Page 28: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Best Practices – Sharing ObjectsConsider local variables/object• No concurrency possible

Consider using ThreadLocal

• One value per thread

Use immutable objects where possible• Immutable objects are always thread-safe• If published correctly

Make use of final• Effect on visibility• Easier reasoning about correctness

Page 29: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Best Practices - Publication

Do not allow this references to escape during construction

• Consider using factory methods

• Do not start a thread from a constructor

• Use inheritance judiciously

• Publish safely

Page 30: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Best Practices – Safe Publication

Publish object reference and object state at the same time

• Static initialiser

• Write to volatile field or AtomicReference

• Store reference into a final field

• Store reference to a field guarded by a lock

Placing an object in a unsynchronized Collection does not work in general

Page 31: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Outline

• Motivation

• Definitions

• JMM in a Nutshell

• The final Keyword

• Conclusions

Page 32: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Beyond Synchronisation

• JMM also defines

– Which reads/writes have to be atomic

– Semantics of wait and notify operations

• Parallel to interrupts

• Neither interrupt nor notify must get lost

– Semantics of sleep and yield

• Do not have any synchronisation semantics

– Semantics of modifying final fields

Page 33: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Conclusions

• JMM specifies when actions of one thread are guaranteed to be visible to another

• Threads run isolated: no guarantees

• Synchronisation actions provide inter-thread dependencies

Page 34: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Conclusions (II)

• final fields provide stronger guarantees(freeze when constructor finishes)

• Publish safely

• Locking can guarantee both: visibility and atomicity; volatile variables can only guarantee visibility.

Page 35: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

References

• Goetz, Brian: Java Concurrency in Practice

• Bloch, Joshua: Effective Java

• Angelika Langer: Overview of the Java Memory Model

• Gosling, James et al.: The Java Language Specification, 3rd edition.

Page 36: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Modifying final fields

• Modification possible – Using reflection

– Triggers an immediate freeze

• Sometimes required– Executors,

– std{in,out,err} handlers

• Yet, discuraged– Require additional compiler knowledge

– Counter-intuitive

Page 37: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Outline

• Motivation

• Definitions

• JMM in a Nutshell

• The final Keyword

• Best Practices

• Diving in…

• Conclusions

Page 38: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Best Pratices

• Locking is not just about mutual exclusion; it is also about memory visibility. To ensure that all thread see the most up-to-date values of shared mutable variables, the reading and writing threads must synchronise on the same lock.

• Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility.

Page 39: The Java Memory Model - Ulm · Java Memory Model •Minimal guarantees the JVM must make about when writes to variables become visible. predictability and ease of programming vs high-performance

Diving In…