Update multiple volatile and jucatomic variables atomic

In order to atomically update two or more volatile variables, should they be locked using synchronized ones, reentrantReadWriteLock, etc.

i.e.

volatile int vVar1, vVar1; // or AtomicInteger

/*** Needs to be updated atomically ***/
void atomicUpdate(int var1, int var2){
  vVar1 = var1;
  vVar2 = var2;
}

      

The same code is for java.util.concurrent.atomic variables.

+3


source to share


4 answers


If you need to assign two values โ€‹โ€‹atomically, changing volatile int

to AtomicInteger

will not solve your race condition problem.

To solve your problem, you basically have two options:

  • Make methods that update variables synchronized

    (and possibly methods that read those variables too)
  • Create a wrapper for your two variables and use the fact that assignment is an atomic operation


Example for option 2:

volatile Vars vars;
void atomicUpdate(int var1, int var2) {
    vars = new Vars(var1, var2);
}

public static Vars {
    private int vVar1;  // volatile if they need to be modified
    private int vVar2;
}

      

Basically, I prefer option 2 as it is non-blocking and allows any data type to be cached.

+5


source


Create a class that encapsulates all of your state variables and then use AtomicReference to refer to them. This eases race conditions when a thread must safely set / check multiple values.

// set initial state
AtomicReference<MyState> ref = new AtomicReference<MyState>();
ref.set(new MyState("abc", "def"));

// .. Thread 1 needs to change the state:
ref.set(new MyState("xyz", "def"));

// .. Thread 2 needs to read the state (consistently):
MyState state = ref.get();
if ("test1".equals(state.a)) { }
else if ("test2".equals(state.b) { }

      



The advantage here is being Thread 2

able to read MyState.a

and MyState.b

sequentially from the same instance MyState

, as opposed to having an instance variable MyState

referencing the change in intermediate checks.

+3


source


I want to update two variables atomically

You can not. There are no atomic operations in the Java language or the Java Standard Library that span more than one variable.

You can probably solve your problem by using a keyword synchronized

, but usage synchronized

is different from using atomistic because for it to work, threads have to communicate with each other.

If there is a certain relationship that must always exist between these two variables (aka, invariant), and if you cannot update the variables without breaking the invariant temporarily, then you must synchronize the code that does the update, and you must also synchronize every other block of code which expects the invariant to be true.

This is because when you write this:

synchronized(foo) { ... }

      

This does not prevent other bottoms from doing anything other than synchronizing on the same object at the same time.


Also note that once you've properly synchronized all variable access, you don't need them to be volatile

. This is because any thread written to memory before releasing a lock is guaranteed to become visible to any other thread that subsequently acquires the same lock.

+2


source


An alternative could be to use a volatile array:

private volatile int[] var;

void update (int var1, int var2) {
  var = new int[] { var1, var2 };
}

      

which will be atomic, but assumes that the rest of your code won't directly access vVar1 and vVar2. Depending on what you are trying to achieve, there may be better options - for example, you could create a safe (usually immutable) safety class for two chains.

+1


source







All Articles