gpt4 book ai didi

java - 如何为对象引用构建延迟初始化线程安全包装器

转载 作者:行者123 更新时间:2023-12-02 10:54:51 24 4
gpt4 key购买 nike

我想实现一个包装类。该类(class)唯一面向公众的内容是:

  • 一个构造函数,它采用逻辑来创建包装类的实例。如Supplier<WrappedType> ,也许吧。
  • 获取包装类实例的方法。

其行为遵循以下规则:创建包装类的逻辑可能会产生副作用,并且只能调用一次。而且,显然,getter 方法实际上应该始终返回相同的包装类实例,这实际上应该是运行传递给构造函数的逻辑的结果。

我认为我的代码可以实现我想要的功能,但我不确定如何测试它是否保证有效,或者是否有更好的方法来实现。

package foo;

import java.util.function.Supplier;

public final class ConcurrentLazyContainer<A> {
private Supplier<A> supplier;
private A value;

public ConcurrentLazyContainer(Supplier<A> supplier) {
this.supplier = supplier;
value = null;
}

public synchronized A get() {
if (value == null) {
value = supplier.get();
supplier = null;
}

return value;
}
}

仅使用 synchronized 即可让我一路到达我想要的地方?也许我的字段也需要不稳定吗?

我编写了一个测试,该测试会启动调用相同包装器的新线程,但在我看来,供应商并没有被多次调用,这很奇怪,因为我真的不明白为什么这里不需要 volatile .

最佳答案

对这个问题的评论是正确的:如果你只访问value synchronized内方法,那么你不需要它是 volatile以及。但是,在某些情况下,您也许可以使用 double-checked locking 来提高性能。 .

public final class Lazy<T> {

private final Supplier<? extends T> initializer;
private volatile T value;

public Lazy(Supplier<? extends T> initializer) {
this.initializer = initializer;
}

public T get() {
T result = this.value;
if (result == null) {
synchronized (this) {
result = this.value;
if (result == null) {
this.value = result = this.initializer.get();
}
}
}
return result;
}

}

此代码基于 Effective Java 中显示的一些示例 Java Concurrency in Practice 。请注意,此代码检查两次以查看是否 resultnull ,一旦超出synchronized block ,一旦进入。这样做的优点是,如果该值已经存在,则无需同步。请注意,使用此策略,value必须是volatile因为它正在 synchronized 之外被访问 block 。

关于java - 如何为对象引用构建延迟初始化线程安全包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51851412/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com