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/
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/
• 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/
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/
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++; } }
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
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
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
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
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
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
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
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)
• 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
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
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
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); }
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; } }
• No lock contention • Scales really well due to the lack of synchronization overhead PERFORMANCE & SCALABILITY 3 • No race conditions NO RISK OF DEADLOCKS