У вас может быть логический флаг (переменная экземпляра), который указывает, был ли вызван b()
или нет. Все потоки, которые входят в синхронизированный блок, проверят это условие перед вызовом b()
.
private boolean isDone = false;
public void code() {
a();
synchronized (this) {
if (!isDone) {
b();
isDone = true;
}
}
c();
}
Только первый поток, получивший блокировку, будет вызывать b()
. После успешного завершения он установит для флага значение true и выйдет из блока. Все последующие потоки, входящие в блок, потерпят неудачу при условии , если , и, следовательно, не будут вызывать b()
.
Если вы не хотите, чтобы другие потоки ожидали синхронизированного блоказаблокировать и хотите продолжить вызывать c()
, вы можете удалить синхронизированное ключевое слово и использовать AtomicBoolean
и использовать его compareAndSet
private AtomicBoolean isDone = new AtomicBoolean(false);
public void code() {
a();
if (isDone.compareAndSet(false, true)) {
b();
}
c();
}
Javadoc из compareAndSet
состояний
Атомно устанавливает значение для данного обновленного значения, если текущее значение {@code ==} ожидаемое значение.
@ return {@code true} в случае успеха. Ложный возврат означает, что фактическое значение не было равно ожидаемому.
Итак, первый поток, который вызывает compareAndSet
, в то время как isDone
имеет значение false, будет успешным. Остальные получат false
в качестве возвращаемого значения и, следовательно, не войдут в блок и могут продолжить.
ОБНОВЛЕНИЕ: Из ваших комментариев
@ user7 Да, я обеспокоен тем, что потоки без необходимости вызывают b (), но (см. Мой другой комментарий) мне нужны те потоки, которые приходят, пока b () работает, чтобы дождаться его завершения, прежде чем они продолжат выполнение c ()
Кажется, вам нужен мой первый раствор.