Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Greater-than compare-and-swap

Tags:

As the title suggests, I'm looking for a compare-and-swap implementation, but with greater-than comparison:

if(newValue > oldValue) {     oldValue = newValue; } 

where oldValue is some global shared state and newValue is private to each thread, without doing this:

synchronized(locker) {     if(newValue > oldValue) {         oldValue = newValue;     }        } 

because I want a non-blocking solution. From studying source codes of other non-blocking operations, I've come up with this (assuming the values are integers):

AtomicInteger oldValue; // shared global variable  ...  public boolean GreaterThanCAS(int newValue) {      while(true) {         int local = oldValue;         if(local == oldValue) {             if(newValue > local) {                  if(oldValue.compareAndSet(local, newValue) {                      return true;  // swap successful                  } // else keep looping             } else {                  return false; // swap failed             }         } // else keep looping     } } 

when // else keep looping happens, it means that another thread has changed the oldValue in the meantime and so I need to loop and try again.

Is this implementation correct (thread-safe)?

like image 557
Tudor Avatar asked Feb 20 '12 15:02

Tudor


People also ask

Why is compare-and-swap better than test and set?

test-and-set modifies the contents of a memory location and returns its old value as a single atomic operation. compare-and-swap atomically compares the contents of a memory location to a given value and, only if they are the same, modifies the contents of that memory location to a given new value.

How do you use compare-and-swap?

Compare and swap is a technique used when designing concurrent algorithms. The approach is to compare the actual value of the variable to the expected value of the variable and if the actual value matches the expected value, then swap the actual value of the variable for the new value passed in.

Why is compare-and-swap atomic?

The compare and the store are atomic: if the store is performed, you are guaranteed that no thread could sneak in and write a value other than old to *ptr. Because a single operation provides the old version of the value and stores a new one, compare-and-swap is said to be an atomic read-modify-write operation.

Can you tell me what a compare-and-swap algorithm is and how you use it when coding in Java?

The compare-and-swap (CAS) instruction is an uninterruptible instruction that reads a memory location, compares the read value with an expected value, and stores a new value in the memory location when the read value matches the expected value. Otherwise, nothing is done.


2 Answers

Since Java 8 this can be simplified with use of updateAndGet:

public boolean greaterThanCAS(int newValue) {     return oldValue.updateAndGet(x -> x < newValue ? newValue : x) == newValue; } 

Note that this would return true also in case when old and new values are equal. Give a try to @Adam's answer if this is not desired behaviour.

like image 102
Vadzim Avatar answered Oct 15 '22 12:10

Vadzim


I see no problems with your implementation, provided that no thread ever decreases the value of the AtomicInteger. If they do, your code is open to race conditions.

Note that the code can be simplified as follows:

public boolean GreaterThanCAS(int newValue) {     while(true) {         int local = oldValue.get();         if(newValue <= local) {              return false; // swap failed         }         if(oldValue.compareAndSet(local, newValue)) {              return true;  // swap successful         }         // keep trying     } } 
like image 38
NPE Avatar answered Oct 15 '22 13:10

NPE