我有一个下面的方法,我想在下面的条件下执行:
- 这个方法应该只执行一次。一旦执行,就无法再次执行,因此如果有人试图再次执行,它应该通过记录一些有用的错误消息
already executed
或任何有用的信息返回。 - 而且它应该只由一个线程执行。那么如果多个线程都在调用下面的方法,那么它应该只被一个线程调用,其他线程应该等待初始化完成?
下面是我的方法:
public void initialize() {
List<Metadata> metadata = getMetadata(true);
List<Process> process = getProcess();
if (!metadata.isEmpty() && !process.isEmpty()) {
Manager.setAllMetadata(metadata, process);
}
startBackgroundThread();
}
这可能吗?我正在使用 Java 7。
最佳答案
@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");
}
}
这样做的原因是 AtomicBoolean.getAndSet(true)
将在一个原子操作中返回先前设置的值并使新值成为 true
。因此,到达您的方法的第一个线程将返回 false
(因为变量已初始化为 false),并且它会以原子方式将其设置为 true。由于第一个线程返回了 false,它将采用 if
语句中的第一个分支,然后您的初始化就会发生。任何其他调用都会发现 wasRun.getAndSet
返回 true
,因为第一个线程将其设置为 true,因此它们将采用第二个分支,您只会收到日志消息你想要的。
CountDownLatch 初始化为 1,因此除第一个线程之外的所有线程都对其调用 await
。它们将阻塞,直到第一个线程调用 countDown
,这会将计数设置为 0,释放所有等待的线程。
关于java - 如何确保该方法仅从一个线程执行一次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42047944/