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