Не имеет ли java.util.concurrent.atomic.AtomicBoolean
метода, который может атомически отрицать/инвертировать значение? Могу ли я сделать это по-другому? Я что-то пропустил?
У AtomicBoolean нет метода negate()?
Ответ 1
Маленький старик... но на самом деле не чувствовал, что ответы были большими.
Необходимо полностью не согласиться с тем, что это не является обычным явлением или полезно только для аппаратного обеспечения. Вы можете захотеть, чтобы ряд потоков переключился на одну переменную с равным вероятностью... Я использовал AtomicLong для создания фальшивого логического. Это было принято из JMS MessageListener, что мне нужно было ответить на определенное сообщение в течение половины времени, а другой - на другую половину.
public class Mock {
private static AtomicLong count = new AtomicLong(0);
public boolean respond() {
long currentCount = count.getAndIncrement();
if (currentCount % 2 == 0) {
return true;
} else {
return false;
}
}
}
Ответ 2
Моя наивная реализация будет следующей:
boolean v;
do {
v=atomicBoolean.get();
} while(!atomicBoolean.compareAndSet(v, !v));
Ответ 3
Решение, предложенное в книге Стандарт безопасного кодирования Oracle CERT для Java:
import java.util.concurrent.atomic.AtomicBoolean;
final class Flag {
private AtomicBoolean flag = new AtomicBoolean(true);
public void toggle() {
boolean temp;
do {
temp = flag.get();
} while(!flag.compareAndSet(temp, !temp));
}
}
Ответ 4
Используя метод AtomicBoolean # compareAndSet() и цикл while вы можете реализовать метод для переключения значения AtomicBoolean в потоке - безопасный способ:
public static boolean negate(AtomicBoolean ab) {
// get the oposite value
boolean newVal = !ab.get();
// try to set the new value if the current value is the oposite of the new value
while (!ab.compareAndSet(!newVal, newVal)) {
// if the value we try to set was already set in the mean-time
// then toggle the new value and try again
newVal = !newVal;
}
// return the value we finally could set
return newVal;
}
Ответ 5
Вы можете эмулировать AtomicBoolean.negate()
, используя AtomicInteger.getAndIncrement()
и рассматривая четные числа как true
а нечетные числа как false
. Фактическое значение числа следует игнорировать, поэтому вам не нужно беспокоиться о целочисленных переполнениях.
Ответ 6
Если вы имеете дело с Java 9 или более поздней версии, я предлагаю:
/**
* Flip the AtomicBoolean.
* Sets the boolean value to false if it is true, and to true if it is false
* with memory effects as specified by {@link java.lang.invoke.VarHandle#setVolatile}.
*
* @param atomicBoolean atomicBoolean
* @return new boolean value of AtomicBoolean
* @see AtomicInteger#accumulateAndGet(int x, IntBinaryOperator accumulatorFunction)
* @since 9
*/
public static final boolean flip(AtomicBoolean atomicBoolean) {
boolean prev = atomicBoolean.get(), next = false;
for (boolean haveNext = false; ; ) {
if (!haveNext) {
next = !prev;
}
if (atomicBoolean.weakCompareAndSetVolatile(prev, next)) {
return next;
}
haveNext = (prev == (prev = atomicBoolean.get()));
}
}
Или, если вы хотите получить это напрямую...