Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Concurrent programming without synchronization

Concurrent programming without synchronization

July 4th, 2015 @ EPAM Tech Talks

Martin Hristov

July 04, 2015
Tweet

More Decks by Martin Hristov

Other Decks in Programming

Transcript

  1. 3 CONFIDENTIAL THREAD SAFETY • … is unfortunately hard to

    be defined. • Because it means different things to different people! • Brian Goetz: • A class is thread-safe when it continues to behave correctly when accessed from multiple threads. • Joseph Albahari: • A program or method is thread-safe if it has no indeterminacy in the face of any multithreading scenario. Image credit: http://www.beaconhillnw.com/2014/09/workplace-safety-signage/
  2. 7 CONFIDENTIAL LOCK-FREE THREAD SAFETY Immutability 1 Compare-And-Swap (CAS) 2

    volatile piggy-backing 3 Thread confinement 4 • Ad-hoc Thread Confinement • Stack Confinement • Thread Confinement with ThreadLocal
  3. 8 CONFIDENTIAL IMMUTABILITY • Immutable objects cannot change their state

    once constructed • Strategy for definition: • No setter methods • All fields private and final • No methods overriding allowed • No this and mutable field references escapes • Thread safety guaranteed by initialization safety (JSR-133) • Safe and simple; consider whenever feasible Image credit: https://www.flickr.com/photos/bala_/4184518104/
  4. 9 CONFIDENTIAL @ThreadSafe public final class CreditCard { private final

    String holder; private final String number; public CreditCard(String holder, String number) { this.holder = holder; this.number = number; } public String getHolder() { return holder; } public String getNumber() { return number; } } THREAD-SAFE IMMUTABILITY (EXAMPLES) NOT THREAD-SAFE @NotThreadSafe final public class ShoppingCart { private CartService cartService; private final List<Item> items; @Autowired public ShoppingCart(List<Item> items, CartService cs) { cartService = cs; cartService.registerCart(this); this.items = Collections .unmodifiableList(items); } public List<Item> getItems() { return items; } }
  5. 10 CONFIDENTIAL @ThreadSafe public final class CreditCard { private final

    String holder; private final String number; public CreditCard(String holder, String number) { this.holder = holder; this.number = number; } public String getHolder() { return holder; } public String getNumber() { return number; } } THREAD-SAFE IMMUTABILITY (EXAMPLES) NOT THREAD-SAFE @NotThreadSafe final public class ShoppingCart { private CartService cartService; private final List<Item> items; @Autowired public ShoppingCart(List<Item> items, CartService cs) { cartService = cs; cartService.registerCart(this); this.items = Collections .unmodifiableList(items); } public List<Item> getItems() { return items; } } Escape of mutable data object reference Escape of this reference during construction
  6. 11 CONFIDENTIAL EFFECTIVE IMMUTABILITY • A special case of immutability

    • Effective immutability is a characteristic of instances rather than classes • An object instance that cannot be mutated via any execution path is effectively immutable • Effectively immutable objects are instances of mutable classes Image credit: https://www.flickr.com/photos/pupski/34237242/
  7. 12 CONFIDENTIAL @NotThreadSafe public final class AirConditioner { private final

    boolean canChange; private short temperature; public AirConditioner(short temperature, boolean canChange) { this.canChange = canChange; this.temperature = temperature; } public void setTemperature(short newTemperature) { if (canChange) { temperature = newTemperature; } else { throw new IllegalStateException(); } } public short getTemperature() { return temperature; } } EFFECTIVE IMMUTABILITY (EXAMPLE) THREAD-SAFE INSTANCE AirConditioner airConditioner = new AirConditioner(24, false);
  8. 13 CONFIDENTIAL @NotThreadSafe public final class AirConditioner { private final

    boolean canChange; private short temperature; public AirConditioner(short temperature, boolean canChange) { this.canChange = canChange; this.temperature = temperature; } public void setTemperature(short newTemperature) { if (canChange) { temperature = newTemperature; } else { throw new IllegalStateException(); } } public short getTemperature() { return temperature; } } EFFECTIVE IMMUTABILITY (EXAMPLE) THREAD-SAFE INSTANCE AirConditioner airConditioner = new AirConditioner(24, false);
  9. 14 CONFIDENTIAL COMPARE-AND-SWAP (CAS) • Non-blocking algorithm for concurrent access

    to shared data • Modifies a value in memory only if it is equal to a given value, otherwise the modification fails • Ensures that the new value is calculated based on up-to-date data • Uses atomic CPU instructions: • CMPXCHG (x86) • CMPXCHGQ (x64) • Available via atomic variables in Java 5.0+ java.util.concurrent.atomic Image credit: http://www.keepcalm-o-matic.co.uk/
  10. 28 CONFIDENTIAL CPU1 CAS EXPLAINED MEMORY 21 21 CPU2 21

    22 22 22 22 20 cas(21,20) write failed
  11. 29 CONFIDENTIAL @ThreadSafe public class AtomicCounter { private final AtomicInteger

    value = new AtomicInteger(0); public int getValue() { return value.get(); } public int increment() { return value.incrementAndGet(); } } THREAD-SAFE CAS vs volatile (EXAMPLES) NOT THREAD-SAFE @NotThreadSafe public class VolatileCounter { private volatile int value = 0; public int getValue() { return value; } public int increment() { return value++; } }
  12. 30 CONFIDENTIAL @ThreadSafe public class AtomicCounter { private final AtomicInteger

    value = new AtomicInteger(0); public int getValue() { return value.get(); } public int increment() { return value.incrementAndGet(); } } THREAD-SAFE CAS vs volatile (EXAMPLES) NOT THREAD-SAFE @NotThreadSafe public class VolatileCounter { private volatile int value = 0; public int getValue() { return value; } public int increment() { return value++; } } • Unsafe operation • The increment operator is not an atomic action: • Read value • Increment by 1 • Write value • Volatile ensures visibility only and not atomicity
  13. 31 CONFIDENTIAL @ThreadSafe public class VolatileCounter { private volatile int

    value = 0; public int getValue() { return value; } public synchronized int increment() { return value++; } } @ThreadSafe public class AtomicCounter { private final AtomicInteger value = new AtomicInteger(0); public int getValue() { return value.get(); } public int increment() { return value.incrementAndGet(); } } THREAD-SAFE CAS vs volatile (EXAMPLES) THREAD-SAFE Lock contention == performance degradation
  14. 32 CONFIDENTIAL VOLATILE PIGGY-BACKING • Allows volatile-like semantics for non-volatile

    variables • Exploits the happens-before order established by JSR-133 • Actions in the same thread cannot be reordered (Program order) • A write to a volatile field happens-before every subsequent read of that field • Volatile writes effectively create a memory fence which flushes CPU cache Image credit: http://www.magic-of-color.com/?p=2127
  15. 33 CONFIDENTIAL public class Point { private int x; private

    int y; private volatile boolean done = false; public void calculateCoordinates() { x = someHeavyweightAlgorithm(…); // x=5 y = someHeavyweightAlgorithm(…); // y=10 sync(); } private void sync() { done = true; } public int getX() { return x; } public int getY() { return y; } public boolean isDone() { return done; } } THREAD #1 VOLATILE PIGGY-BACKING (EXAMPLE) THREAD #2 public class CoordinatesConsumer { private Point point; public CoordinatesConsumer(Point point) { this.point = point; } public void doSomething() { while (!point.isDone()) ; // Busy wait int x = point.getX(); // x=5 int y = point.getY(); // y=10 } } • x and y get visible in Thread #2 even though they are not volatile • they piggyback on done which is volatile
  16. 34 CONFIDENTIAL VOLATILE PIGGY-BACKING PRECAUTIONS • Volatile piggybacking is fragile!

    Use at your own risk! • Ensures only visibility, thus applicable for “single writer / multiple readers” scenarios only • It does not ensure compound atomicity in case of multiple writes/reads. Image credit: http://www.noomii.com/blog/5949-warning-union-info-centre-scam
  17. 35 CONFIDENTIAL THREAD CONFINEMENT • Thread confinement is a simple

    yet powerful technique used to achieve thread safety without synchronization. • The simple idea: • If data is only accessed from a single thread, no synchronization is needed. • Examples: • Swing – visual components are confined to the event dispatch thread • JDBC Connection Pools
  18. 36 CONFIDENTIAL CONFINEMENT MECHANISMS • Java does not provide language-level

    mechanisms that enforce thread confinement. • Must be enforced by the application design and its implementation • Java provides mechanisms that help maintaining confinement: • Access modifiers • Local variables • ThreadLocal Image credit: http://www.treatmentadvocacycenter.org/about-us/our-blog/69-no-state/2109-solitary-confinement-like-gasoline-on-fire
  19. 37 CONFIDENTIAL AD-HOC THREAD CONFINEMENT • Developer is completely responsible

    to confine object to thread. Language features (like local variables, access modifiers) are not used • State must be shared in a specific way: • All shared data – marked as volatile • Only a single thread must be able to write to the shared data - requires developer’s carefulness and discipline • Not recommended approach (due to its fragility)
  20. 38 CONFIDENTIAL STACK CONFINEMENT • Special case of thread confinement

    • An object can only be reached through a local variable • The developer must ensure that the object reference does not escape the method • Ensures thread safety even if the confined object itself is not thread-safe
  21. 39 CONFIDENTIAL STACK CONFINEMENT • Example: public static String format(Date

    date) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); return df.format(date); } • We only have one reference to the SimpleDateFormat object • The reference is held in a local variable and therefore confined to the executing thread
  22. 40 CONFIDENTIAL STACK CONFINEMENT private static final DateFormat df =

    new SimpleDateFormat("yyyy-MM-dd"); public static String format(Date date) { return df.format(date); }
  23. 41 CONFIDENTIAL STACK CONFINEMENT private static final DateFormat df =

    new SimpleDateFormat("yyyy-MM-dd"); public static String format(Date date) { return df.format(date); } No longer “stack confined”
  24. 42 CONFIDENTIAL THREAD CONFINEMENT WITH ThreadLocal java.lang.ThreadLocal<T>: • Provides thread-local

    variables • Each thread has its own, independently initialized copy of the variable (accessed via ThreadLocal’s get() or set() methods) • ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread
  25. 43 CONFIDENTIAL THREAD CONFINEMENT WITH ThreadLocal Example: DateFormat is not

    thread-safe, so we use thread confinement: private static final ThreadLocal<DateFormat> tdf = new ThreadLocal<DateFormat>() { protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } }; public String threadConfined(Date date) { return tdf.get().format(date); }
  26. 44 CONFIDENTIAL OBJECT ESCAPE • An object is said to

    have escaped if it is published before intended. Image credit: http://www.humbersidefire.gov.uk/your-safety/safety-in-the-home/escape
  27. 45 CONFIDENTIAL OBJECT ESCAPE (EXAMPLE) • Store a reference in

    a public static field, where any class and thread could see it: public static List<String> unsafeList; public void initialize() { unsafeList = new ArrayList<String>(); } • Return a reference from a non-private method: class UnsafeCurrencies { private String[] currencies = new String[] {"USD", "GBP", "BGN", "EUR", "AUD"}; public String[] getCurrencies() { return currencies; } }
  28. 46 CONFIDENTIAL JAVA OBJECT ESCAPE (EXAMPLE) BYTECODE … final com.threadconfinement.ThisEscape

    this$0; … 0: aload_0 1: aload_1 2: putfield #1 // Field this$0:Lcom/threadconfinement/ThisEscape; 5: aload_0 6: invokespecial #2 // Method java/lang/Object."<init>":()V 9: return … public class ThisEscape { public ThisEscape(EventSource source) { source.registerListener( new EventListener() { public void onEvent(Event e) { doSomething(e); } }); } }
  29. 47 CONFIDENTIAL JAVA OBJECT ESCAPE (EXAMPLE) BYTECODE … final com.threadconfinement.ThisEscape

    this$0; … 0: aload_0 1: aload_1 2: putfield #1 // Field this$0:Lcom/threadconfinement/ThisEscape; 5: aload_0 6: invokespecial #2 // Method java/lang/Object."<init>":()V 9: return … public class ThisEscape { public ThisEscape(EventSource source) { source.registerListener( new EventListener() { public void onEvent(Event e) { doSomething(e); } }); } }
  30. 48 CONFIDENTIAL BENEFITS • No accidental complexity SIMPLICITY 2 1

    • No lock contention • Scales really well due to the lack of synchronization overhead PERFORMANCE & SCALABILITY 3 • No race conditions NO RISK OF DEADLOCKS