You must use synchronization in order to ensure visibility of memory writes across threads
Locking is not just about mutual exclusion, it is also about memory visibility, and guarantees that any changes in previous thread before releasing lock are actually visible in the next thread which will acquire the lock
We want not only to prevent one thread from modifying the state of an object when another is using it, but also to ensure that when a thread modifies the state if ab object, other threads can actually see the changes that were made
If we make sure the visibility of a object, will it also ensure visibility of its internal state?
When a thread reads a variable without synchronization, it may see a stale value, but at least it sees a value that was actually placed by some other thread rather than some random value, this is called Out-of-thin-air safety
This safety applies to all variables except: 64 but numeric variables (double and long) that are not declared volatile
JMM specifies fetch and store operations to be atomic, but for non-volatile long and double variables, JVM is permitted to treat a 64 bit read or write as two 32 bit operations
Even if are okay with stale data, You must use long and double as volatile or guarded by lock. Otherwise even the stale data represented by them will be wrong
Publishing
Publishing means making an object available to code outside of its current scope
return data from non-private method
passing data into another class method
An object that is published when it should not have been, is said to have escaped
The technique to make data accessible by only single thread is called thread confinement
Data which is not shared by multiple threads is automatically thread-safe
Ad-hoc thread confinement describes when the responsibility for maintaining thread confinement falls entirely on the implementation
Example is to make sure the read-modify-write operations is always done by single thread by design of your program
It should be avoided since it is fragile
Techniques:
Stack Confinement
ThreadLocal
Stack Confinement
aka within-thread or thread-local usage
Local variables are intrinsically confined to the executing thread
They exist on the thread’s stack which is not accessible by other threads
For primitive variables it is always stack confined since it is not possible to publish its reference (primitive variable hold value not reference)
For non-primitive objects, we need to be careful as to not publish its reference
Using non-thread safe object in within-thread context is still thread safe
ThreadLocal
ThreadLocal allows you to associate a per-thread value with a value-holding object
Methods:
ThreadLocal.withInitial(() → {});
threadLocal.set(value);
threadLocal.get();
public class TestConcurrency { private static final ThreadLocal<Integer> threadLocalValue = ThreadLocal.withInitial(() -> 0); public static void main(String[] args) { // Set the value of the thread-local variable for the main thread threadLocalValue.set(10); // Create and start a new thread Thread newThread = new Thread(() -> { // Get the value of the thread-local variable for this thread // will print 0 System.out.println("Thread-local value in newThread: " + threadLocalValue.get()); }); newThread.start(); // Get the value of the thread-local variable for the main thread // will print 10 System.out.println("Thread-local value in main thread: " + threadLocalValue.get()); }}