Reputation: 327
Suppose I have the following code:
AtomicBoolean condition;
condition = new AtomicBoolean(false);
(...)
while(!condition.get()){
// do some stuff
}
I know that condition.get()
is atomic, but, is !condition.get()
atomic as well?
I mean, could it happen that one Thread
read the boolean value atomically and then it were interrupted before applying the !
operation, so that another Thread
gets into the loop before? If that's the case, would it be better to use a function such as:
private synchronized boolean checkNegatedCondition(AtomicBoolean cond){
return !cond.get();
}
(...)
while(checkNegatedCondition(condition)){
// do some stuff
}
Thanks in advance.
Upvotes: 4
Views: 3523
Reputation: 8589
Atomicity isn't the issue. Two threads can read an atomic variable concurrently. So any number of threads could read the value and enter the loop based on its negation. It doesn't matter if ! is atomic. It acts on a thread-local value.
To use atomics for exclusion you usually need AtomicBoolean.compareAndSet(boolean,boolean)
.
v.compareAndSet(a,b)
will only set v
to value b
if it is a
and return true. Otherwise if v doesn't have the value a
at the start, it does nothing and returns false.
In pseudo-code it's
synchronized public boolean compareAndSet(boolean a,boolean b){
if(v!=a) return false;
v=b;
return true;
}
But (very important) takes place atomically so all other operations on v can be ordered before or after it.
AtomicBoolean condition = new AtomicBoolean(false);
//...
if(condition.compareAndSet(false,true)){
//Only one thread can get here unless condition is set back...
}
if you wanted to use this as a 'pseudo' synchronized block you might code:
while(!condition.compareAndSet(false,true));
//Only one thread can get here at a time...
condition.set(false);
This could be described as'spin' locking. Because threads 'waiting' to enter the controlled section 'spin' round and round in the loop until released.
This may show poorer performance than synchronized
because that operating system will normally 'suspend' waiting threads and progress other tasks.
However spin-locks can show better performance in cases where contention is very low (i.e. little or no waiting is required).
Pro-Tip: In practice it is good practice to put condition.set(false) in a
finally` block:
while(!condition.compareAndSet(false,true));
try {
//Only one thread can get here at a time...
}finally{
condition.set(false);
}
Otherwise an exception thrown in one thread will permanently lock out
any access to that section of code.
Upvotes: 3
Reputation: 140613
One has to be precise here:
get()
operation is supposed to be atomic, and because of the "further" guarantees for any atomic class, it is also guaranteed to be "visible" to other threads looking at the same object (atomic in the sense that all the **set* methods are atomic, so it is not possible to get()
something that is "half-set")And just to be sure: the core thing here is not "atomicity" - because a get()
just returns a value (and in contrast to a double, there is even just a single bit/byte affected). In other words: AtomicBoolean
is mainly about making sure that changes to the object are visible to all threads using the object.
Buty yes, assuming that AtomicBoolean is a field of a class, and multiple threads are calling a method like:
public void foo() {
while(!condition.get() ...
it is theoretically possible that
But: assume that we had a "protected" getNot()
, the final result would be the same:
In both cases, the first thread would enter the loop!
Upvotes: 4
Reputation: 1658
AtomicBoolean.get is not about being atomic, but instead about being thread-safe.
atomic would be a concept related to read and write stuff, and your question does not mention anything like that.
if you want to read and write (or write and read) atomically, there are other methods on AtomicBoolean (like getAndSet or compareAndSet). From your question it might seem you are looking for something more related to that (cannot tell for sure from your question details).
If what you want is not to retrieve and change a value atomically, but instead retrieve until it is changed in other place of your code after some logic (so not atomically), then you are looking for locking.
Upvotes: 0