Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Controlling race condition at startup

I have some code that I want to have some one time initialisation performed. But this code doesn't have a definite lifecycle, so my logic can be potentially invoked by multiple threads before my initialisation is done. So, I want to basically ensure that my logic code "waits" until initialisation is done.

This is my first cut.

public class MyClass {
    private static final AtomicBoolean initialised = new AtomicBoolean(false);

    public void initialise() {
        synchronized(initialised) {
            initStuff();
            initialised.getAndSet(true);
            initialised.notifyAll();
        }
    }

    public void doStuff() {
        synchronized(initialised) {
            if (!initialised.get()) {
                try {
                    initialised.wait();
                } catch (InterruptedException ex) {
                    throw new RuntimeException("Uh oh!", ex);
                }
            }
        }

        doOtherStuff();
    }
}

I basically want to make sure this is going to do what I think it's going to do -- block doStuff until the initialised is true, and that I'm not missing a race condition where doStuff might get stuck on a Object.wait() that will never arrive.

Edit:

I have no control over the threads. And I want to be able to control when all of the initialisation is done, which is why doStuff() can't call initialise().

I used an AtomicBoolean as it was a combination of a value holder, and an object I could synchronize. I could have also simply had a "public static final Object lock = new Object();" and a simple boolean flag. AtomicBoolean conveniently gave me both. A Boolean can not be modified.

The CountDownLatch is exactly what I was looking for. I also considered using a Sempahore with 0 permits. But the CountDownLatch is perfect for just this task.

like image 778
Will Hartung Avatar asked Dec 12 '25 07:12

Will Hartung


2 Answers

That's a strange mix of library and built-in concurrency controls. Something like this is much cleaner:

public class MyClass {

  private static final CountDownLatch latch = new CountDownLatch(1);

  public void initialise() {
    initStuff();
    latch.countDown();
  }

  public void doStuff() {
    try {
      latch.await();
    } catch (InterruptedException ex) {
      throw new RuntimeException("Uh oh!", ex);
    }
    doOtherStuff();
  }

}
like image 195
erickson Avatar answered Dec 14 '25 20:12

erickson


A synchronized block will automatically block other threads. Just use a simple lock object + status variable:

public class MyClass {
    private static boolean initialised;
    private static final Object lockObject = new Object();

    public void initialise() {
        synchronized (lockObject) {
            if (!initialised) {
                initStuff();
                initialised = true;
            }
        }
    }

    public void doStuff() {
        initialise();
        doOtherStuff();
    }
}
like image 32
Brett Kail Avatar answered Dec 14 '25 19:12

Brett Kail