@ ShayHaned的解决方案使用锁定.您可以通过AtomicBoolean使其更高效,如:
AtomicBoolean wasRun = new AtomicBoolean(false);
CountDownLatch initCompleteLatch = new CountDownLatch(1);
public void initialize() {
if (!wasRun.getAndSet(true)) {
List metadata = getMetadata(true);
List 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");
}
}
以上假设您不必等待startBackgroundThread中的工作完成.如果你这样做,解决方案就变成:
AtomicBoolean wasRun = new AtomicBoolean(false);
CountDownLatch initCompleteLatch = new CountDownLatch(1);
public void initialize() {
if (!wasRun.getAndSet(true)) {
List metadata = getMetadata(true);
List 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");
}
}
这样做的原因是AtomicBoolean.getAndSet(true)将在一个原子操作中返回先前设置的值并使新值为true.因此,获取方法的第一个线程将返回false(因为变量初始化为false),并且原子地将其设置为true.由于第一个线程返回false,它将在if语句中获取第一个分支,并且您的初始化将会发生.任何其他调用都会发现wasRun.getAndSet返回true,因为第一个线程将其设置为true,因此它们将获取第二个分支,您将获得所需的日志消息.
CountDownLatch初始化为1,因此除第一次调用之外的所有线程都在等待它.它们将阻塞,直到第一个线程调用countDown,这将把计数设置为0,释放所有等待的线程.