Reputation: 5736
Consider the following code
static AtomicBoolean initialized = new AtomicBoolean(false);
static AtomicBoolean initStarted= new AtomicBoolean(false);
public static void init() {
if (!initialized.get() && !initStarted.getAndSet(true)) {
doInitialization();
initialized.set(true);
}
// start waiting
while (!initialized.get());
// finished waiting
doMoreStuff();
}
It achieves what I want to make sure doMoreStuff()
is not called until doInitialization()
has completed and only the very first thread should call doInitialization()
.
My question is, how does this compare to using synchronized
block to the whole init()
method?
As I see AtomicReference also use infinite loop (a.k.a busy waiting) to waste CPU cycle to do update (see AtomicReference#getAndUpdate()
), so may be it is not so bad to do the same here as a synchronisation method?
If infinite loop is so bad (e.g. wasting CPU cycle) then why don't AtomicReference use synchronized
to stop or wake up threads?
Upvotes: 1
Views: 1213
Reputation: 311
AtomicBoolean.getAndSet works if you only would like allow a single thread to access a specific block, just as you did, but I would not recommend to use it in a if-statement with other variables that might change, even though this case probably would have been safe. You while loop is however consuming 100% CPU while waiting, so I suggest that you use a CountDownLatch instead.
AtomicBoolean initialized = new AtomicBoolean(false);
CountDownLatch lock = new CountDownLatch(1);
public void init() throws InterruptedException {
if (!initialized.getAndSet(true)) {
doInitialization();
lock.countDown();
}
// start waiting
lock.await();
// finished waiting
doMoreStuff();
}
Upvotes: 2
Reputation: 262852
AtomicReference#getAndUpdate is not using busy waiting to block until an external condition has changed.
134 * Atomically sets to the given value and returns the old value.
135 *
136 * @param newValue the new value
137 * @return the previous value
138 */
139 public final V getAndSet(V newValue) {
140 while (true) {
141 V x = get();
142 if (compareAndSet(x, newValue))
143 return x;
144 }
145 }
The loop is expected to run just once except in the case of contention.
The only way compareAndSet
can fail is if another thread did the same thing at exactly the same time.
This is called "retry-loop" and should be executed only a very few number of times (approximately once).
Upvotes: 3