我知道AtomicReference有compareAndSet,但我觉得我想做的是这个
private final AtomicReference<Boolean> initialized = new AtomicReference<>( false );
...
atomicRef.compareSetAndDo( false, true, () -> {
// stuff that only happens if false
});
Run Code Online (Sandbox Code Playgroud)
这可能也有效,可能会更好。
atomicRef.compareAndSet( false, () -> {
// stuff that only happens if false
// if I die still false.
return true;
});
Run Code Online (Sandbox Code Playgroud)
我注意到有一些新的功能结构,但我不确定它们中是否有任何一个是我正在寻找的。
任何新的构造都可以做到这一点吗?如果是这样,请提供一个例子。
更新
为了简化我的问题,我试图找到一种不太容易出错的方法来保护代码,以“为对象做一次”或(真的)懒惰的初始化方式,我知道我团队中的一些开发人员compareAndSet感到困惑。
“为对象执行一次”中的保护代码
具体如何实现取决于您希望其他线程同时尝试执行相同的操作。如果你只是让它们运行通过 CAS,它们可能会观察到处于中间状态的事物,而成功的一个线程会执行其操作。
或(真正的)惰性初始化方式
如果您将其用于惰性初始化器,则该构造不是线程安全的,因为“已初始化”布尔值可能会被一个线程设置为 true,然后在另一个线程观察 true 状态但读取空结果时执行该块。
如果可以接受多个并发/重复的初始化尝试,并且一个对象最终获胜而其他对象被 GC 丢弃,则可以使用Atomicreference::updateAndGet 。更新方法应该是无副作用的。
否则,您应该只使用带有可变引用字段的双重检查锁定模式。
当然,您始终可以将其中任何一个打包到一个高阶函数中,该函数返回一个Runnable或Supplier,然后将其分配给最终字段。
// == FunctionalUtils.java
/** @param mayRunMultipleTimes must be side-effect-free */
public static <T> Supplier<T> instantiateOne(Supplier<T> mayRunMultipleTimes) {
AtomicReference<T> ref = new AtomicReference<>(null);
return () -> {
T val = ref.get(); // fast-path if already initialized
if(val != null)
return val;
return ref.updateAndGet(v -> v == null ? mayRunMultipleTimes.get() : v)
};
}
// == ClassWithLazyField.java
private final Supplier<Foo> lazyInstanceVal = FunctionalUtils.instantiateOne(() -> new Foo());
public Foo getFoo() {
lazyInstanceVal.get();
}
Run Code Online (Sandbox Code Playgroud)
您可以通过这种方式轻松封装各种自定义控制流和锁定模式。这是我自己的两个。。
compareAndSet如果更新完成则返回 true,如果实际值不等于预期值则返回 false。
所以只需使用
if (ref.compareAndSet(expectedValue, newValue)) {
...
}
Run Code Online (Sandbox Code Playgroud)
也就是说,我不太理解您的示例,因为您将 true 和 false 传递给以对象引用作为参数的方法。你的第二个例子并没有做与第一个例子相同的事情。如果第二个是你想要的,我想你追求的是
ref.getAndUpdate(value -> {
if (value.equals(expectedValue)) {
return someNewValue(value);
}
else {
return value;
}
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2219 次 |
| 最近记录: |