Usage of AtomicBoolean
You are attempting to use the AtomicBoolean to satisfy two requirements:


The first thread to access the data loads it while all others wait until it's been loaded the first time.
Another thread can update the data for future callers.


Neither of these is working perfectly.


While only one thread will load the data, all other threads will receive null without waiting until that first thread completes the loading process.
Because the list of objects is updated after the memory barrier, other threads are not guaranteed to see the new reference immediately.


Solving the first problem is simple enough: use a CountDownLatch to cause all incoming threads to block until the first list of objects is set. Ideally the system would start another thread to specifically load the data rather than letting the first random thread to come along and do it. This isn't necessary (see below), but it's much cleaner.

For the second problem, wrap the list of objects in an AtomicReference to supply a correct memory barrier. You might be thinking, "Oh no! Not two synchronizers for each access!" but Java's synchronization primitives have improved greatly over the years, and the atomic value holders are even cheaper than full synchronization.

public class HibernateDao extends SomeOtherClass implements Dao {
    private CountDownLatch dataLoaded = new CountDownLatch();
    private AtomicReference&lt;List&lt;SomeObject&gt;&gt; data = new AtomicReference&lt;&gt;();

    @Override
    public List&lt;SomeObject&gt; getAllSomeObjects() {
        dataLoaded.await();          // wait until first countDown call
        return data.get();
    }

    @Override
    public void updateAllSomeObjects(Collection&lt;SomeObject&gt; someObjects) {
        replaceAll(SomeObject.class, someObjects);
        data.set(someObjects);
        dataLoaded.countDown();      // release any waiting threads
    }
}


If you really must have the first thread perform the initial loading rather than a separate thread that calls updateAllSomeObjects on its own, you can add back your beloved AtomicBoolean. This would be my last choice, however.


  Note that while you can use if (!ab.getAndSet(true)) it's clearer to use compareAndSet as it indicates that you're performing a tested set rather than allowing any thread to set the new value.


    private AtomicBoolean firstCaller = new AtomicBoolean();

    @Override
    public List&lt;SomeObject&gt; getAllSomeObjects() {
        if (firstCaller.compareAndSet(false, true)) {
            updateAllSomeObjects((List&lt;SomeObject&gt;) getHibernateTemplate().loadAll(SomeObject.class));
        }
        else {
            dataLoaded.await();      // wait until first countDown call
        }
        return data.get();
    }