我有以下结构:
public void someMethod(){
//DO SOME STUFF
try{
doSomeProcessing();
}
catch (Exception e){
loadSomeHeavyData();
doSomeProcessing();
}
}
someMethod
方法可能 被多个线程并发调用。 doSomeProcessing
可能 抛出异常(它在后端使用了一些可能过时的数据)。
如果抛出异常,则 loadSomeHeavyData();
会执行一些耗时的任务,比如说“更新”所有当前数据,然后我可以调用 doSomeProcessing();
。< br/>
问题:如何确保 loadSomeHeavyData();
只被调用一次?如果我在 loadSomeHeavyData();
的条目中放置一些原子标志,那么我无法确定何时应该清除它。
我该如何解决这个问题?请注意:我无法修改 doSomeProcessing();
,因为它是一个外部 API,我正在使用装饰器模式来使用它。
最佳答案
您的 loadSomeHeavyData
方法可以使用阻塞机制让所有线程等待直到完成更新,但只让其中一个线程实际执行更新:
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();
}
}
注意我的假设:
- 您希望所有线程等待加载完成,以便它们可以使用更新后的数据第二次调用
doSomeProcessing
- 您只能调用一次
loadSomeHeavyData
,否则您将需要重置标志和 CountdownLatch(这可能不是最合适的机制)。
编辑
您最近的评论表明您实际上想多次调用 loadSomeHeavyData
,只是一次不超过一次。
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();
}
}
关于java - 如何确保一个方法只被多个线程调用一次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13356702/