Tirafesi
Tirafesi

Reputation: 1479

How to swap boolean value in multi-threaded environment?

1.

volatile boolean bool = false;
// ...
bool = !bool;

2.

volatile AtomicBoolean bool= new AtomicBoolean(false);
// ...
bool.set(!bool.get());

If there are multiple threads running, and one of them needs to swap the value of bool and making the new value visible for other threads, do these 2 approaches have the same problem of allowing for another thread's operation to happen in-between the read and write, or does AtomicBoolean assure that nothing will happen in-between the call to .get() and .set()?

Upvotes: 4

Views: 986

Answers (4)

OutOfNPE
OutOfNPE

Reputation: 306

As it has been already mentioned, you can not simply swap value using neither volatile boolean nor AtomicBoolean in one line.

There are two ways you can do it, which also showed above:

  • using one "global" lock/synchronization
  • via while loop and AtomicBoolean.compareAndSet

Whereas the first solution looks easier and just works, in my opinion, in most cases it would be considered as a bad practise and should be avoided. Unless you have a really high count of simultanious modifications of this field by multiple threads, the second solution should outperform the first one.

Nevertheless, if you really favor simplicity and do not need a better performance knowing the cost of this decision, choose the first.

To add my contribution, I have noticed that you defined your atomic variable as volatile, and, just in case, warn you, that if you do not reassign this field and it can be made final, better do it final. volatile applies only to the actual field value and if you do not change it (which you do not using set/compareAndSet methods of AtomicBoolean) and you have made sure, that other threads will see the initialized value (final does it) there is no much sense to use it.

Upvotes: 1

Robert Kock
Robert Kock

Reputation: 6038

AtomicBoolean cannot assure nothing will happen between the get() and set().
You could create 3 methods get(), set() and swap() that synchronize on the same object.

You could try something like this:

public class SyncBoolean
{
  public SyncBoolean()
  {
    value = false;
  }

  public synchronized boolean get()
  {
    return (value);
  }

  public synchronized void set(boolean newValue)
  {
    value = newValue;
  }

  public synchronized void swap()
  {
    value = !value;
  }

  private boolean value;

} // class SyncBoolean

Upvotes: 4

assylias
assylias

Reputation: 328785

Both versions could fail for the reason you have given. One option would be:

boolean b;
do {
  b = bool.get();
} while (! bool.compareAndSet(b, !b));

Upvotes: 3

Nikolas
Nikolas

Reputation: 44476

Neither bool = !bool nor bool.set(!bool.get()) are atomic. Wrapping the operation to the synchronized block helps because two threads can't enter it on the same object twice.

synchronized(this) {
    bool.set(!bool.get());
}

Upvotes: 1

Related Questions