【问题标题】:java AtomicInteger accumulateAndGet is applied应用了java AtomicInteger accumAndGet
【发布时间】:2019-12-01 14:04:35
【问题描述】:

我有一个将值存储为 AtomicInteger 的 Counter 类。该类应该是线程安全的。我有方法boolean consume(int number),如果counter >= number,应该递减计数器并返回true,如果counter < number,不应该更改计数器并返回false

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();
}

但是accumulateAndGetsais的javadoc:

该功能应该没有副作用,因为它可以重新应用 当尝试更新由于线程之间的争用而失败时。

所以,我的解决方案有副作用。使用安全吗?如果不是,我怎样才能得到相同的结果?

【问题讨论】:

  • 我会说是的,因为副作用是幂等的:如果第一次更新失败并且完成了新的尝试,结果将被正确更新。如果你在二元运算符中增加了一个外部值,那就另当别论了。
  • 我强烈建议你不使用这种方法会更清楚。仅将标准compareAndSet 循环写为包含两个出口的for (;;)。如果您迫切需要单入口单出口 (SESE) 样式,即使是标准循环也可以保留足够的本地信息以确定其走向。

标签: java concurrency atomicinteger


【解决方案1】:

从描述中,听起来好像你想要这样的东西:

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;
           }
        }
    }
}

因为它可能会在尝试更新失败时重新应用 线程之间的争用。

问题中的代码可以执行一次或多次,但如果不方便使用便捷方法则无济于事。

【讨论】:

    猜你喜欢
    • 2017-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2017-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多