当前位置: 首页 > 知识库问答 >
问题:

volatile+不可变的holder对象=线程安全?

储仲渊
2023-03-14
public class VolatileCachedFactorizer extends GenericServlet implements Servlet {

  private volatile OneValueCache cache = new OneValueCache(null, null);

  public void service(ServletRequest req, ServletResponse resp) {
    BigInteger i = extractFromRequest(req);
    BigInteger[] factors = cache.getFactors(i);
    if (factors == null) {             
        factors = factor(i);  //----------> thread A
        cache = new OneValueCache(i, factors);  //---------> thread B
    }
    encodeIntoResponse(resp, factors);
  }   
 }

public class OneValueCache {

  private final BigInteger lastNum;
  private final BigInteger[] lastFactors;

  public OneValueCache(BigInteger i, BigInteger[] lastFactors){
    this.lastNum = i;
    this.lastFactors = lastFactors;
  }

  public BigInteger[] getFactors(BigInteger i){
    if(lastNum == null || !lastNum.equals(i))
        return null;
    else
        return Arrays.copyOf(lastFactors, lastFactors.length);
  }

}

类OneValueCache是不可变的。但是我们可以更改变量缓存的引用。

但我不能理解为什么VolateCachedFactorizer类是线程安全的。

对于两个线程(线程A和线程B),如果线程A和线程B同时到达factors==null,那么两个线程A和B都将尝试创建OnEvalueCache。然后线程A到达factors=factor(i)而线程B同时到达cache=new OneValueCache(i,factors)。然后线程A将创建一个OnEvalueCache,它覆盖threadB创建的值(OneValueChange是不可变的,但是可以更改对变量缓存的引用)。

共有1个答案

黄宏大
2023-03-14

因此,两个线程计算因子(一个为67,另一个为89),然后将它们的结果存储到cache变量中。最后一个设置变量的线程获胜。假设第一个线程是最后一个将其因子存储在缓存中的线程。因此,高速缓存包含67的因子。

如果后续执行请求67的因子,它将从缓存中获取这些因子(因为缓存不是空的,并且包含67的因子)。如果它请求另一个数的因子,它不会从缓存中获取它们,将因此计算这些因子,并将它们存储在缓存中,希望下面的请求将请求相同个数的因子。

不能保证两个线程不会从相同的数字计算因子。此代码提供的唯一保证是,如果缓存当前包含所请求的数字的因子,则将返回这些缓存的因子(而不是其他数字的因子或数据竞争导致的不一致数据

 类似资料:
  • 从静态初始值设定项初始化对象引用 将对它的引用存储到volatile字段或atomicreference 将对它的引用存储到正确构造的对象的最后一个字段 将对它的引用存储到由锁正确保护的字段中。 但是,我对第二个成语感到困惑。因为只能保证引用对另一个线程是可见的,但它没有它所引用的对象构造的同步。那么它如何保证可变对象是正确构造的,构造这个对象的线程是什么,被另一个线程打断了呢?

  • 下面的代码片段使用多个线程,使用AtomicInteger计算到1亿。我有10个Writer线程来模拟写争用,还有一个Reader线程来模拟读争用。作者和读者还共享一个易变的布尔变量作为毒药。 但是,只有读线程可以退出,而写线程不能退出。尽管将变量声明为volatile,但为什么读线程不能看到更新的值? 附言:如果我把布尔值包在一个对象中,它就会工作。

  • 我得到的是它们是线程安全的。 杰里米·曼森博客的片段- 因为this引用存储在lastconstructed中“,因此转义构造函数 请建议。

  • 问题内容: 在Java中,我知道关键字可以提供变量的可见性。问题是,如果变量是对可变对象的引用,是否还为该对象内部的成员提供可见性? 在下面的示例中,如果多个线程正在访问和更改线程,它是否可以正常工作? 例 问题答案: 这是关于volatile的一些细节的旁注说明。在这里写这个是因为评论太多了。我想举一些例子说明挥发性如何影响可见性,以及在jdk 1.5中如何改变。 给出以下示例代码: 此测试代码

  • 问题内容: 我正在努力使可变对象与不可变对象有关。使用可变对象会带来很多负面影响(例如,从方法中返回字符串数组),但是我很难理解它的负面影响。使用可变对象的最佳实践是什么?您是否应尽可能避免使用它们? 问题答案: 好吧,这有几个方面。 没有参考身份的可变对象会在奇数时间导致错误。例如,考虑使用基于值的方法的 : 当实例用作键时,实例在映射中“丢失”,因为实例和相等性基于可变值。这些值在映射之外更改

  • 关于一次从多个线程访问局部变量的几个问题: > < li> 我有多个线程写入和读取变量值,我是否应该同步访问它? 变量每隔几秒钟从 Thread1 更新一次,每隔几秒钟从 Thread2 读取和更新到数据库。 如果我没有任何逻辑并且没有任何并发问题,会出现哪些问题? 我应该为此使用volatile吗? 编辑: 我想强调的是,我没有任何并发问题。这是我的具体方案: 一个。我的变量名称是 ,它测量 p