java - 有没有办法对 AtomicReference 设置锁定

标签 java concurrency

我想这样做:

  • 读取 AtomicReference 中的值
  • 基于旧值执行复杂的逻辑来创建新值
  • 替换 AtomicReference 中的值

在此过程中,我希望其他线程等待直至完成。所以我需要给线程加一个读锁,逻辑完成后释放锁。

下面是我的尝试:

AtomicReference<String> version = new AtomicReference<>();
String v = version.get(); // Is there way to put a read lock here so that when other thread try to read it, they will have to wait until the current thread finish
if (v.equals("old")) { 
   String newVersion = getNewVersion(); // execute a complex logic
   version.set(newVersion);
}
// release the lock here

最佳答案

像这样阻止所有读取线程(通过get)是不可能的。您需要使用其他工具来执行此操作,并且需要在使用 version 的任何地方使用它们。

与您的想法最接近的事情是使用 AtomicReference 的原子方法,例如 updateAndGet:

AtomicReference<String> version = new AtomicReference<>();
version.updateAndGet(v -> {
    if (v.equals("old")) {
        return getNewVersion();
    }
    else {
        return v;
    }
});

此方法利用原子 CAS指令实现non-blocking synchronization .

此方法的一个简单实现是:

public T updateAndGet(UnaryOperator<T> f) {
    T curr, next;
    do {
        curr = get();
        next = f.apply(curr);
    } while (!compareAndSet(curr, next));
    return next;
}

如果第一个给定参数等于实际当前值,则方法 compareAndSet(即用于访问底层 CAS 指令的外观)返回 true,否则 false 。如果第一个给定参数等于实际当前值,则当前值将替换为第二个参数(比较和交换)。

现在我为什么要解释这个?因为使用 updateAndGet 接近您想要的,但不一样:

  • getNewVersion 可能会运行多次。当当前值被 curr = get(); 和 CAS 调用之间的另一个线程更改时,就会发生这种情况。
  • curr = get(); 和 CAS 调用之间发生的读取会获取旧值,而不是像您的想法那样获取新值。不过这个时间跨度很小,不用担心。
  • 不涉及锁,这是使用 AtomicXXX 类的最大好处之一。您希望它们轻量且快速。

关于java - 有没有办法对 AtomicReference 设置锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64593262/

相关文章:

java - 如何改变 Android Studio 中 listView 中项目的数量?

java - 接口(interface)如何执行操作

java - 为什么公共(public)静态最终数组是一个安全漏洞?

Java 判断当前平台是否支持窗口化

java - ConcurrentHashMap中的遍历

java - 默认调试显示 30 年的到期日期。 keystore 到期日期为 365 天

Java 并发实践 : Listing 3. 12 和 3.13

api - 列出所有 Asana 工作区任务

sql-server - 使用 EF Core 2.1 和 SQL Server 进行正确的并发处理

java - 在启动时控制竞争条件