I have a below method which I want to execute on below conditions:
already executed
or anything useful. Below is my method:
public void initialize() {
List<Metadata> metadata = getMetadata(true);
List<Process> process = getProcess();
if (!metadata.isEmpty() && !process.isEmpty()) {
Manager.setAllMetadata(metadata, process);
}
startBackgroundThread();
}
Is this possible to do? I am working with Java 7.
Use a variable to flag the call to the method. Check this immediately and return if the flag is set. In C/C++ you can use a static local variable to store the flag.
Yes, you can use lock for this. Create a private synchronization object in your class, acquire the lock on this object and only one thread at a time will be able to execute the code within the lock block.
Here is other way you can restrict thread execution number: Use a ThreadGroup. Create your thread in a ThreadGroup. You get active thread count from a ThreadGroup, which you can use to check how many threads are present and can prevent creation of new thread.
Mutex locks allow only one thread at a time to execute a specific section of code, or to access specific data. Read/write locks permit concurrent reads and exclusive writes to a protected shared resource.
@ShayHaned's solution uses locking. You can make it more efficient via AtomicBoolean
like:
AtomicBoolean wasRun = new AtomicBoolean(false);
CountDownLatch initCompleteLatch = new CountDownLatch(1);
public void initialize() {
if (!wasRun.getAndSet(true)) {
List<Metadata> metadata = getMetadata(true);
List<Process> process = getProcess();
if (!metadata.isEmpty() && !process.isEmpty()) {
Manager.setAllMetadata(metadata, process);
}
startBackgroundThread();
initCompleteLatch.countDown();
} else {
log.info("Waiting to ensure initialize is done.");
initCompleteLatch.await();
log.warn("I was already run");
}
}
The above assumes you don't have to wait for the work in startBackgroundThread
to complete. If you do, the solution becomes:
AtomicBoolean wasRun = new AtomicBoolean(false);
CountDownLatch initCompleteLatch = new CountDownLatch(1);
public void initialize() {
if (!wasRun.getAndSet(true)) {
List<Metadata> metadata = getMetadata(true);
List<Process> process = getProcess();
if (!metadata.isEmpty() && !process.isEmpty()) {
Manager.setAllMetadata(metadata, process);
}
// Pass the latch to startBackgroundThread so it can
// call countDown on it when it's done.
startBackgroundThread(initCompleteLatch);
} else {
log.info("Waiting to ensure initialize is done.");
initCompleteLatch.await();
log.warn("I was already run");
}
}
The reason this works is that AtomicBoolean.getAndSet(true)
will, in one atomic operation, return the value that was previously set for and make the new value be true
. So the first thread to get to your method will get false
returned (since the variable was initialized to false) and it will, atomically, set it to true. Since that first thread had false returned it'll take the first branch in the if
statement and your initialization will happen. Any other calls will find that wasRun.getAndSet
returns true
since the first thread set it to true so they'll take the 2nd branch and you'll just get the log message you wanted.
The CountDownLatch is initialized to 1 so all threads other than the first call await
on it. They will block until the first thread calls countDown
which will set the count to 0 releasing all the waiting threads.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With