Что использует AtomicReference.compareAndSet() для определения?

StackOverflow https://stackoverflow.com/questions/1869959

  •  18-09-2019
  •  | 
  •  

Вопрос

Скажем, у вас есть следующий класс

public class AccessStatistics {
  private final int noPages, noErrors;
  public AccessStatistics(int noPages, int noErrors) {
    this.noPages = noPages;
    this.noErrors = noErrors;
  }
  public int getNoPages() { return noPages; }
  public int getNoErrors() { return noErrors; }
}

и вы выполняете следующий код

private AtomicReference<AccessStatistics> stats =
  new AtomicReference<AccessStatistics>(new AccessStatistics(0, 0));

public void incrementPageCount(boolean wasError) {
  AccessStatistics prev, newValue;
  do {
    prev = stats.get();
    int noPages = prev.getNoPages() + 1;
    int noErrors = prev.getNoErrors;
    if (wasError) {
      noErrors++;
    }
    newValue = new AccessStatistics(noPages, noErrors);
  } while (!stats.compareAndSet(prev, newValue));
}

В последней строке while (!stats.compareAndSet(prev, newValue)) как это compareAndSet метод определить равенство между prev и newValue?Это AccessStatistics класс, необходимый для реализации equals() метод?Если нет, то почему?В javadoc указано следующее: AtomicReference.compareAndSet

Атомарно устанавливает значение данного обновленного значения, если текущее значение == ожидаемое значение.

...но это утверждение кажется очень общим, и учебники, которые я читал по AtomicReference, никогда не предлагают реализовать метод равенства() для класса, заключенного в AtomicReference.

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

Это было полезно?

Решение

Он сравнивает ссылки точно так же, как если бы вы использовали оператор ==.Это означает, что ссылки должны указывать на один и тот же экземпляр.Object.equals() не используется.

Другие советы

На самом деле, это так нет сравните предыдущее и новое значение!

Вместо этого он сравнивает значение, хранящееся в статистике, со значением prev, и только если они совпадают, обновляет значение, хранящееся в статистике, до newValue.Как сказано выше, для этого используется оператор равенства (==).Это означает, что статистика будет обновляться только тогда, когда prev указывает на тот же объект, который хранится в stats.

Он просто проверяет равенство ссылок на объекты (т.е. ==), поэтому, если ссылка на объект, хранящаяся в AtomicReference, изменилась после того, как вы получили ссылку, ссылка не изменится, поэтому вам придется начинать все сначала.

Ниже приведены некоторые исходные коды AtomicReference.AtomicReference относится к ссылке на объект.Эта ссылка представляет собой изменчивую переменную-член в экземпляре AtomicReference, как показано ниже.

private volatile V value;

get() просто возвращает последнее значение переменной (как это делают летучие значения в режиме «происходит раньше»).

public final V get()

Ниже приведен наиболее важный метод AtomicReference.

public final boolean  compareAndSet(V expect, V update) {
        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

Метод CompareAndSet(expect,update) вызывает метод CompareAndSwapObject() небезопасного класса Java.Этот вызов метода unsafe вызывает собственный вызов, который вызывает одну инструкцию процессора.«ожидать» и «обновлять» - каждая ссылка на объект.

Если и только если переменная-член экземпляра AtomicReference «значение» ссылается на тот же объект, на который ссылается «ожидание», этой переменной экземпляра теперь присваивается «обновление», и возвращается «истина».В противном случае возвращается false.Все делается атомарно.Ни один другой поток не может перехватить их.Поскольку это операция одного процессора (магия современной компьютерной архитектуры), она часто выполняется быстрее, чем использование синхронизированного блока.Но помните, что когда несколько переменных необходимо обновлять атомарно, AtomicReference не поможет.

Я хотел бы добавить полноценный работающий код, который можно запустить в eclipse.Это прояснило бы многие путаницы.Здесь 22 пользователя (темы MyTh) пытаются забронировать 20 мест.Ниже приведен фрагмент кода, за которым следует полный код.

Фрагмент кода, в котором 22 пользователя пытаются забронировать 20 мест.

for (int i = 0; i < 20; i++) {// 20 seats
            seats.add(new AtomicReference<Integer>());
        }
        Thread[] ths = new Thread[22];// 22 users
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new MyTh(seats, i);
            ths[i].start();
        }

Ниже приведена ссылка на github для тех, кто хочет увидеть работающий полный код, небольшой и лаконичный.https://github.com/sankar4git/atomicReference/blob/master/Solution.java

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top