@ Решение 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, чтобы они заняли 2-ю ветку, и вы получите только сообщение журнала.
CountDownLatch инициализирован до 1, так что все потоки, отличные от первого вызова await
на нем. Они будут блокироваться до тех пор, пока первый поток не вызовет countDown
, который установит счетчик на 0, освободив все ожидающие потоки.
Если вы хотите, чтобы убедиться, что часть кода выполняется ровно один раз, чем я думаю, что положить его в классе статический инициализатор перечислимого типа является так близко, как вы можете получить. JVM гарантирует, что это будет вызываться не более одного раза за загрузчик классов. Но лучше этого, я не думаю, что есть ясный способ дать такую гарантию. Может быть, если бы вы рассказали больше о вашем прецеденте? – korolar
У меня есть этот метод в одном из моих классов, который инициализирует все наши метаданные и как только инициализация завершена, то только я хочу двигаться вперед в своем приложении. – user1950349
Не помещал бы его в статический инициализатор этого класса? – korolar