Разница между getAndSet и compareAndSet в AtomicBoolean

Название потока должно быть самообъяснимым... Я немного запутался между спецификациями нижеприведенных методов AtomicBoolean учебный класс:

  • java.util.concurrent.atomic.AtomicBoolean#compareAndSet
  • java.util.concurrent.atomic.AtomicBoolean#getAndSet

Моя сборка состоит в том, что оба будут приводить к одинаковому поведению при использовании в качестве логического предложения в if состояние:

public class Test {
  private AtomicBoolean flag = AtomicBoolean(false);

  public void processSomeAction() {
    if (flag.getAndSet(false)) { // Shouldn't this be similar to flag.compareAndSet(false)
      // process some action
    }
  }
  //...
  private void internalMutatorMethod() {
    // do some staff then update the atomic flag
    flas.set(true);
  }
}

Предполагая, что я хочу получить текущее значение флага и обновить его автоматически, не должны ли оба метода работать одинаково?

Я был бы очень признателен за любые объяснения относительно того, как и когда использовать каждый из них, если мне не хватает внутренних различий.

4 ответа

Решение

Документация довольно понятна.

  • getAndSet -> "Атомно устанавливается на заданное значение и возвращает предыдущее значение."
  • compareAndSet -> "Атомно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение."

Не удивительно, compareAndSet принимает два аргумента.

В вашем конкретном случае:

  • if (flag.getAndSet(false)) установит flag в false только если его предыдущее значение было true
  • Это было бы эквивалентно if (flag.compareAndSet(true, false))

Вы можете посмотреть на код для лучшего понимания:

public final boolean getAndSet(boolean newValue) {
    for (;;) {
        boolean current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}

В getAndSet, если значение логического значения изменилось между вами get() старое значение и время, когда вы пытаетесь изменить его значение, compareAndSet не изменит свое значение. Следовательно, getAndSet звонки compareAndSet в цикле, пока логическое значение не будет установлено на новое значение.

Что касается вашего примера кода:

flag.getAndSet(false) возвращает старое значение AtomicBoolean. С другой стороны, flag.compareAndSet(x,false) (обратите внимание, что есть два аргумента) возвращает, был ли изменен AtomicBoolean, или другими словами, он возвращает, было ли старое значение AtomicBoolean равным x.

Когда я проверил реализацию, я обнаружил следующее

public final boolean getAndSet(boolean newValue) {
    for (;;) {
        boolean current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}

Также при проверке Javadoc, compareAndSet устанавливает значение только в том случае, если сравнение проходит getAndSet просто установите значение и верните предыдущее значение.

Поток немного старый, но никто не упомянул, что getAndSet будет более эффективным, чем CompareAndSet. CAS - очень дорогая инструкция (на всех архитектурах ЦП, поэтому JVM здесь не имеет значения). Так что они на самом деле не эквивалентны.

Что касается OP, оба метода выдают одинаковое поведение, но он не будет иметь одинаковую производительность, используйте getAndSet, когда можете.

Другие вопросы по тегам