简体   繁体   中英

Atomic variables over Volatile

由于原子变量是易变的,即使您只需要易变性方面,始终使用原子变量是否有任何缺点?

A Variable cannot be atomic. There is a clear difference between Atomicity and Volatile nature.

Atomicity: If only one thread can execute a set of instruction at a given time, the operation is called Atomic.

Volatile: A volatile nature ensures visibility. If a thread modify some volatile state the other threads get most recent updated state.

Examples :

volatile boolean flag; 


public void flipTheFlag(){
  if(flag == true){
      flag = false;
  }else{
      flag = true;
  }
}

If multiple threads are working on operation flipTheFlag, the value of flag will be uncertain even though the flag is volatile variable. That's why operation flipTheFlag need to be Atomic. We can make the flipTheFlag operation atomic just by adding keyword 'synchronized'.

  1. When after creation of the final Atomic object different threads use the object to change the internal state, everything works as if volatile .

    However there is an extra object instance around. Costs memory and speed performance. It should in this case be constant/effectively final, and its creation should be done before an other thread will have access.

  2. An other aspect - which correctness I actually do not remember from the java reference but did read elsewhere -, is that with several fields, when one field is volatile on its modification also the other fields will be updated for other threads.

  3. Atomic constants (or similar constant arrays of 1 item) still have a mutable state and are sometimes abused to collect aggregated results with a Stream operation which can only access constants. This means Atomic does not imply a multithreading usage.

  4. In x = x + c; ( volatile x ) you will read the latest x , but after adding c an other thread might change x and you still will assign a stale sum to x. Here atomicity is required. Or if (x > 0) x = c; .

So to answer the question: depending on the brittle context they are somewhat interchangeable. I can see why you prefer Atomic, but there are simple cases where volatile is considerably more performant, especially in fine grained concurrency.

A last remark: I am not totally confident, whether I am entirely correct here.

From a concurrency perspective there is no difference between:

final AtomicInteger foo1 = new AtomicInteger();

And

volatile int foo2;

A foo1.get/set is the same as reading of writing to the foo2. Both will provide atomicity, visibility and ordering guarantees. If you look in the code of eg AtomicInteger, you will see a volatile int variable.

The primary use-cases for an Atomic is that it is very easy to do read modify write operations like incrementing a counter. And that you have access to more relaxed forms of ordering like getRelease and setAcquire. But you can do the same thing using AtomicFieldReference and VarHandles (although the syntax is less pretty).

One drawback of atomic is extra memory usage and indirection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM