I have the following structure:
public void someMethod(){
//DO SOME STUFF
try{
doSomeProcessing();
}
catch (Exception e){
loadSomeHeavyData();
doSomeProcessing();
}
}
The method someMethod
may be called concurrently by many threads. The doSomeProcessing
may throw an exception (it is using some data in the backend that could become obsolete).
If an exception is thrown then loadSomeHeavyData();
does some timeconsuming task that let's say "updates" all the current data and I am able to call doSomeProcessing();
.
Problem: How can I make sure that loadSomeHeavyData();
is called only once? If I put some atomic flag in the entry of loadSomeHeavyData();
then I can not be sure when this should be cleared.
How can I solve this? Just a note: I can not modify doSomeProcessing();
as it is an external API and I am using decorator pattern to use it.
Your loadSomeHeavyData
method could use a blocking mechanism to make all threads wait until it has finished its update, but only let one of them actually do the update:
private final AtomicBoolean updateStarted = new AtomicBoolean();
private final CountDownLatch updateFinished = new CountDownLatch(1);
public void loadSomeHeavyData() {
if (updateStarted.compareAndSet(false, true)) {
//do the loading
updateFinished.countDown();
} else {
//update already running, wait
updateFinished.await();
}
}
Note my assumptions:
doSomeProcessing
a second time with updated dataloadSomeHeavyData
once, ever - if not you will need to reset the flag and the CountdownLatch (which would then probably not be the most appropriate mechanism).EDIT
Your latest comment indicates that you actually want to call loadSomeHeavyData
more than once, just not more than once at a time.
private final Semaphore updatePermit = new Semaphore(1);
public void loadSomeHeavyData() {
if (updatePermit.tryAcquire()) {
//do the loading and release updatePermit when done
updatePermit.release();
} else {
//update already running, wait
updatePermit.acquire();
//release the permit immediately
updatePermit.release();
}
}
Using the synchronized
keyword:
public synchronized void someMethod(){
//doStuff
}
You assure that only one thread enters at a time.
To assure that the method is called only once, there is no special language feature; you could create a static variable of type boolean which is set to true by the first thread entering the method. When calling the method always check that flag:
public class MyClass {
private static boolean calledMyMethod;
public synchronized void someMethod() {
if(calledMyMethod) {
return;
} else {
calledMyMethod = true;
//method logic
}
}
}
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