# atomic | | visibility | compound operations | |:-------- | ---------- | ------------------- | | function | volatile | atomic variable | ###### tags: `java`,`concurrent`,`volatile` 單步驟process >ref: https://ithelp.ithome.com.tw/articles/10229833 > ![](https://i.imgur.com/naj4oxO.png) i++ 非原子性 (read+write) 包含讀取 i=i+1 多步驟, multi thread不能保證結果 Reading, updating, and writing. If two or more threads try to update the value at the same time, then it may not update properly. --- ### volatile, not replacement of synchronize block ![](https://i.imgur.com/1pegwb5.png) * A write to a volatile field happens-before every subsequent read of that field. * modifying its value immediately affects the actual memory storage for the variable. * volatile forces all threads to get latest value of the variable from main memory instead of cache. * only read the lastest data in main memory, owing to no locking the update doesn't gaurantee thread-safe. #### visibility: change by one thread can be visible to other threads. #### mutual exculsion : one thread only can execute a block of code at a given time, or do updates on shared data. :::info volatile never cached => read from main memory(only visibility is confirmed) 不保證同時update時的結果 ![](https://i.imgur.com/rnoiLnq.png) ![](https://i.imgur.com/CrldhWX.png) ::: #### happens before guarantee The happens-before guarantee guarantees that: Reads from and writes to other variables cannot be reordered to occur after a write to a volatile variable, if the reads / writes originally occurred before the write to the volatile variable. * jvm 多core進行 code reorder , volatile variable 相對其他operation的先後順序不可改變 ### volatile doesn't solve race condition ![](https://i.imgur.com/0UfgFI9.png) --- ### synchronize * First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object. * Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads. ![](https://i.imgur.com/f809KlA.png) ```java= synchronized (this){ //lock on this object in heap // incrementing counter // total of max times for (int i = 0; i < max; i++) { count++; } } ``` [範例](https://www.youtube.com/watch?v=71dgtPrbToE) update value will write directly to main memory ![](https://i.imgur.com/jlQvqB3.png) --- volatile: read , field use synchronize: read and write , only block of code and method(not field) ![](https://i.imgur.com/yaxI3Wf.png) ### atomicXXX : thread-safe, lock-free ```java= set(int value): Sets to the given value get(): Gets the current value lazySet(int value): Eventually sets to the given value compareAndSet(int expect, int update): Atomically sets the value to the given updated value if the current value == the expected value addAndGet(int delta): Atomically adds the given value to the current value decrementAndGet(): Atomically decrements by one the current value ``` ref:[source-stacokoverflow](https://stackoverflow.com/questions/9749746/what-is-the-difference-between-atomic-volatile-synchronized) ```java= private AtomicInteger counter = new AtomicInteger(); public int getNextUniqueIndex() { return counter.getAndIncrement(); } ``` The AtomicInteger class uses CAS (compare-and-swap) low-level CPU operations (no synchronization needed!) They allow you to modify a particular variable only if the present value is equal to something else (and is returned successfully). So when you execute getAndIncrement() it actually runs in a loop (simplified real implementation): ```java= int current; do { current = get(); } while(!compareAndSet(current, current + 1)); //only when the compareandset's current is same as current then do the current+1, or reget the current ``` So basically: read; try to store incremented value; if not successful (the value is no longer equal to current), read and try again. The compareAndSet() is implemented in native code (assembly). 有點像optimistic concurrency #### synchronize block * only one thread can execute them at a time * When using non-volatile variables within synchronized blocks, Java ensures both visibility and atomicity through the synchronized keyword. #### synchronize block get variable The thread will invalidate its local cache and read the latest values from main memory. #### synchronize block flush value Any changes made to variables within the synchronized block are flushed to the main memory, making them visible to other threads. --- ### sychronize test - non-synchronize print ```java= public class Counter extends Thread { int count = 0; public void run() { int max = 1_000_000_00; for (int i = 0; i < max; i++) { count++; } System.out.println(count); // read uncommitted like } } public class CounterImpl { public static void main(String[] args) throws InterruptedException { // Instance of Counter Class Counter c = new Counter(); // Defining Two different threads Thread first = new Thread(c, "First"); Thread second = new Thread(c, "Second"); // Threads start executing first.start(); second.start(); // main thread will wait for // both threads to get completed first.join(); second.join(); } } ``` result ``` 100043743 // print race with second.start(), then must larger than 1_000_000_00 199905019 ``` --- ### sychronize test - synchronize print ```java= import lombok.SneakyThrows; public class VolatileRaceConditionExample { private int counter = 0; @SneakyThrows public void increment() { synchronized (this){ System.out.println("init counter value: " + counter); for (int i = 0; i < 1000; i++) { counter++; // Now this is an atomic operation } } Thread.sleep(500); System.out.println("med counter value: " + counter); } public int getCounter() { return counter; } public static void main(String[] args) { VolatileRaceConditionExample example = new VolatileRaceConditionExample(); Runnable task = () -> { example.increment(); }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Final counter value: " + example.getCounter()); } } ``` result ``` init counter value: 0 -- any one start init counter value: 1000 -- after first block med counter value: 2000 -- after 2 sync block med counter value: 2000 -- after 2 sync block Final counter value: 2000 ```