Java AtomicInteger накапливать AndGet применяется - PullRequest
1 голос
/ 01 декабря 2019

У меня есть класс Counter, который хранит значение как AtomicInteger. Этот класс должен быть потокобезопасным. У меня есть метод boolean consume(int number), который должен уменьшить счетчик и вернуть true, если counter >= number, и не должен менять счетчик и вернуть false, если counter < number

class Counter {
   AtomicInteger counter = new AtomicInteger(initialValue);

   boolean consume(int number) {
     counter.accumulateAndGet(number, (prev, next) -> {
            if (number <= prev) {
                return prev - number;
            } else {
                // not modify the previous number;
                return prev;
            }
        });
       return ???
   }
}

И я не знаю, еслифункция применена или нет. Я нашел следующее решение

boolean consume(int number) {
    AtomicBoolean result = new AtomicBoolean(false);
    counter.accumulateAndGet(number, (prev, next) -> {
            if (number <= prev) {
                result.set(true);
                return prev - number;
                // function applied
            } else {
                result.set(false);
                // not modify the previous number;
                return prev;
            }
    });
    return result.get();
}

, но javadoc accumulateAndGet sais:

Функция должна быть без побочных эффектов, так как она может быть повторно применена при попыткеобновления не выполняются из-за конфликта между потоками.

Итак, мое решение имеет побочные эффекты. Это безопасно для использования? Если нет, как я могу получить тот же результат?

1 Ответ

0 голосов
/ 02 декабря 2019

Из описания это звучит так, как будто вы хотите что-то вроде:

class Counter {
    private final int initialValue = 42; // make compile

    /** Non-negative count. */
    private final AtomicInteger counter = new AtomicInteger(initialValue);

    public boolean consume(int number) {
        for (;;) {
           int old = counter.get();
           int next = old-number;

           if (next >= 0) {
               if (counter.compareAndSet(old, next)) {
                   return true;
               };
           } else {
               return false;
           }
        }
    }
}

, поскольку оно может быть повторно применено, если попытки обновления не удаются из-за конфликта между потоками.

Код в вопросе подходит для того, чтобы быть выполненным один или несколько раз, но это не помогает использовать удобные методы, если они не удобны.

...