user1589188
user1589188

Reputation: 5736

Using Atomic and infinite loop to do synchronisation in JAVA

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

Answers (2)

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

Thilo
Thilo

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

Related Questions