Startup race status monitoring

I have code that I want to execute with a single initialization. But this code does not have a specific life cycle, so my logic could potentially be called by multiple threads before my initialization. Therefore, I basically want to make sure that my logic code β€œwaits” until initialization is complete.

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 that this will do what I think it will happen - block doStuff while true is initialized, and that I will not miss the race conditions when doStuff can get stuck on the object. wait (), which will never appear.

Edit:

I have no control over the threads. And I want to be able to control when all initialization is done, so doStuff () cannot call initialise ().

I used AtomicBoolean, as it was a combination of the owner of the value, and an object that I could synchronize. I could also just have a "public static final object Lock = new Object ();" and a simple boolean flag. AtomicBoolean conveniently gave me both. Boolean value cannot be changed.

CountDownLatch is exactly what I was looking for. I also considered using Sempahore with 0 permissions. But CountDownLatch is perfect for this task.

+3
source share
5 answers

This is a strange combination of library and concurrency built-in controls. Something like this is a lot 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(); } } 
+6
source
Block

A synchronized automatically blocks other threads. Just use a simple lock object + state 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(); } } 
+2
source

It is best to use a static initializer (as mentioned by SB):

 public class MyClass { public static void doInitialize() { ... } public void doStuff() { doOtherStuff(); } static { doInitialize(); } } 

This will be done once before any other code is allowed. If you always need to initialize at any time when the class is used, then there will be no performance, since the class will not be loaded until it is used. See the answers to this question for more details.

+1
source

You use AtomicBoolean always from within a synchronized block. It doesn't make much sense, since only one thread can access it. Atomic variables are intended for use in non-fixed solutions - you can get and set the value as an uninterruptible power supply.

I assume that you are looking for a solution without blocking after the initialization has occurred:

 public class MyClass { private static final AtomicBoolean initialised = new AtomicBoolean(false); public void initialise() { if (!intialized.get()) { synchornized (this) { if (!initialized.getAndSet(true)) doInitialize(); } } } public void doStuff() { initialize(); doOtherStuff(); } 

You can also do this with a simple volatile boolean , which is actually a bit more efficient than AtomicBoolean.

0
source

This is correct at startup, why not wait to start other threads until initialization is complete?

In addition, you can execute a stream-dependent IsComplete boolean value that is set to false until it is set to true using the initialization procedure.

0
source

Source: https://habr.com/ru/post/1401437/


All Articles