3

How to make sure the initialize() method is called only once? Below is the thread unsafe version which I would like to refactor to use AtomicBoolean. All I want is that initialize() is only called once

if (!initialized) 
{
   initialize();
   initialized = true;
}
Aravind Yarram
  • 78,777
  • 46
  • 231
  • 327

4 Answers4

5

An atomic boolean will not be enought for you, because a second thread entering the code block will fall throught even if there has no initialization been done yet. Try this, which will block a second, parallel only if the first has not completed yet, and will be very fast when initialization has done:

volatile boolean initialized = false;

private final Object LOCK = new Object();

public void ensureInitialized() {
    if( !initialized ) {
        synchronized(LOCK) {
            if( !initialized ) {
                initialize();
                initialized = true;
            }
        }    
    }
}

This is also know as the double-checked locking ideom, and this way it is done right.

Daniel
  • 27,718
  • 20
  • 89
  • 133
3
private final AtomicBoolean initialized = new AtomicBoolean(false);


//in some method:

if(!initialized.getAndSet(true))
{
    initialize();
}
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 2
    I don't think that is safe. It _will_ guarantee that initialize() is only called once, but the second thread to hit the getAndSet() will not be delayed until the first thread has finished the initialisation. – Paul Cager May 12 '11 at 22:33
  • 4
    ...hence, it will believe the object will have been initialized while this is not the case. This solution is not valid and should not be used. – Jérôme Verstrynge May 14 '11 at 21:13
0
class SomeClass {
    private AtomicBoolean isInitialized = new AtomicBoolean(false);

    private void someMethod() {
        if (!isInitialized.compareAndSet(false, true)) {
            initialize();
        }
    }

}
alexandr.opara
  • 454
  • 2
  • 7
0

In fact, you don't need an atomic boolean with the following code:

public class YourClass() {

    volatile boolean initialized = false;

    public void ensureInitialized() {

        if ( initialized ) return;

        synchronized(this) {
            if (!initialized) {
                initialize();
                initialized = true;
            }
        }

    }

    // The code of this method could be moved
    // into the synchronized statement above
    public void initialize() { ... };

}

Since the initialization code is only going to be called once, there is no real benefit to using an AtomicBoolean.

Synchronizing on 'this' may take a bit more time, but so does the creation of an AtomicBoolean. Both operations happen only once.

Overall, this solution uses less memory.

EDIT: Updated solution

Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
  • 1
    -1, this might lead to double initialization. And I don't know we just try to post my solution, after I did write it down, and then you also do it wrong. – Daniel May 13 '11 at 05:58
  • Yes, I forgot the if in the synchronized. I have updated my solution. – Jérôme Verstrynge May 13 '11 at 14:02
  • 1
    Still wrong. If you set the initialized variable before doing the initialization, a second thread might still pass before initialization done. Sorry. – Daniel May 14 '11 at 20:32
  • Your right, a second thread may believe that initialization has been performed while this is not the case. I have updated my answer. – Jérôme Verstrynge May 14 '11 at 21:02
  • Btw. there is a reason that the code of the initialize() should NOT be moved in the synchronized statement: Then the ensureInitialized() will be posssible to large for the hotspot compiler to compile into fast machine code. Since the initialize method will be called only once, it is very good practice to have it in a separate method. Sorry. – Daniel May 17 '11 at 18:13
  • Sorry, but by exposing the initialize code in a separate method, you also take the risk of having other code call it inappropriately. And, including the initialize code in the 'synchronize' does not prevent optimization by the hot-spot compiler. Moreover, speculating about the behavior of this compiler is bad practice, because you don't control this parameter. – Jérôme Verstrynge May 17 '11 at 18:26
  • I disagree. Do it like you would. – Daniel May 17 '11 at 19:37