java - 使用 volatile 发布不可变对象(immutable对象)安全吗?

标签 java concurrency volatile java.util.concurrent

最近读了《Java并发实践》 节 --> “3.4.2 示例:使用 volatile 发布不可变对象(immutable对象)”。

但是;我无法安静地理解它。 情况是这样的!

不可变对象(immutable对象)是:

@Immutable
class OneValueCache {
    private final BigInteger lastNumber;
    private final BigInteger[] lastFactors;
    public OneValueCache(BigInteger i, BigInteger[] factors) {
        lastNumber = i;
        lastFactors = Arrays.copyOf(factors, factors.length);
    }
    public BigInteger[] getFactors(BigInteger i) {
        if (lastNumber == null || !lastNumber.equals(i))
            return null;
        else
            return Arrays.copyOf(lastFactors, lastFactors.length);
    }
}

假设我们有一个这样的 servlet

public class MyServlet {
private volatile OneValueCache immutableValue;
.
.

public void service(){
            .
            // what this function do : gets value from immutable object increments its
            // value and creates new Immutable object and put it back.
            // 
            .
    immutableValue = new OneValueCache( lastNumber, lastFactor[]);
    .
    .
    .
}
.
.
.
}

根据《MyServlet 是线程安全的》一书,因为它使用 volatile 关键字发布不可变对象(immutable对象)!

但是我认为这里有问题!

假设:

线程 1 在时间 0 将值从 immutableValue 读取到其堆栈变量中;

线程 2 在时间 0 将值从 immutableValue 读取到其堆栈变量;

线程 1 在时间 1 中递增堆栈变量中的值并创建新的 OneValueCache 对象 - 不可变 - 并将其放入 immutableValue 字段变量中;

线程 2 在时间 2 中递增堆栈变量中的值并创建新的 OneValueCache 对象 - 不可变 - 并将其放入 immutableValue 字段变量中;

这样我们就丢失了 Thread1 更新,因此这里没有 ThreadSafty!

相反,书上说:

<强>" 这种不可变持有者对象的组合 由一个不变量相关的多个状态变量,以及一个用于 确保其及时可见性,允许 VolatileCachedFactorizer 是线程安全的 即使它没有显式锁定。 “

任何人都可以帮助我我在这里缺少什么吗?

p.s:为了更清楚地说明,我知道这里保持数据一致性。我们不能有无效的 OneValueCache 状态。但正如我的线程序列所示,这里有可能丢失更新。所以这个类不是线程安全的!

最佳答案

不变性意味着线程安全,因为一旦创建,任何线程都无法修改它,因此值在线程之间保持一致。

在上面的示例中,“private volatile OneValueCache immutableValue”一次只能保存一个值,因此如果线程 1 先更新,然后线程 2 更新引用值,则最后一个值将由“onevaluecache”表示,并更新线程 1由于您只存储一个引用值,将会丢失。

在您提到的步骤中,OneValueCache 的状态在任何时候都不一致,因此它是线程安全的。

编辑:状态不一致的一些情况是:

  1. 如果 immutableValue 变量不是 volatile 的,那么每个线程都会存储自己的副本,这意味着缓存将无法正常工作。

  2. 如果 OneValueCache 类是可变的,则多个线程将同时更改其值,这意味着状态将不一致,因此不是线程安全的。

关于java - 使用 volatile 发布不可变对象(immutable对象)安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16119871/

相关文章:

c# - .NET 多线程、 volatile 和内存模型

java - 我应该同步静态易失变量吗?

c - 在 C 中正确丢弃 volatile 变量内容的替代方法是什么?

java - 如何使用Java在quartz中从下午2点到晚上11点每30秒触发一次触发器?

java - 发送完所有未决消息后关闭套接字

java - 如何使用 Java 6 针对 Java 1.4 库构建 Java 项目?

java - 查找二维数组中的最大元素

python - Python中的并行递归函数

java - 创建n个变量java

scala - Scala Actor 中的 Thread.sleep