不稳定与最终。 final在这里有什么用?

时间:2014-09-04 05:18:02

标签: java

下面是实践中来自并发的代码片段。

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);  
}  
}


//Volatile is not enough to make VolatileCachedFactorizer thread safe? Why we need final   specifier in OneValueCache. 
public class VolatileCachedFactorizer implements Servlet {  
  private volatile OneValueCache cache = new OneValueCache(null, null); 
  //Servlet service method. 
  public void service(ServletRequest req, ServletResponse resp) {  
     BigInteger i = extractFromRequest(req);  
     BigInteger[] factors = cache.getFactors(i);
     //Check factors are null or not.  
     if (factors == null) {  
       factors = factor(i);  
       cache = new OneValueCache(i, factors);  
     }  
     encodeIntoResponse(resp, factors);  
  }  
} 

在OneValueCache中将字段声明为final是什么用法。 " volatile OneValueCache缓存"确保该对象对所有其他线程可见,并且我假设在volatile写入之前的写入对所有其他线程都是可见的。

3 个答案:

答案 0 :(得分:4)

最终字段使OneValueCache不可变,从而使其成为线程安全的。它们还具有由JLS定义的特殊语义,特别是,任何线程都能够看到正确构造的对象,并将最终字段初始化为其唯一正确的值。

如果不是这种情况,并且字段碰巧不是最终的,那么其他线程可能无法看到更改,即使在构造函数中也是如此,因为没有最终字段,就没有施工安全保证。

JCIP解释说OneValueCache只是一个用于保存两位数据的不可变引用类。这比更新方法中的两个字段更安全,因为它不是原子的。然后,OneValueCache在servlet中变为volatile,因为它需要更改,但是是原子赋值,因此不需要同步。

答案 1 :(得分:2)

他们是两回事。 一般来说,

volatile - >创建一个内存屏障,强制刷新缓存中的数据并强制从主内存中读取数据。因此,所有线程始终可以获取此特定字段的更新数据。

final - >

  
      
  1. 用于基元 - >指定值不能更改

  2.   
  3. 非基元 - >引用不能改变(即引用不能指向另一个对象)。   对于 immutable 的对象/字段,您需要确保 final 字段可以传递地访问它,并且它的引用不会被转义。

    < / LI>   

PS:最终不变性是两个不同的概念。所以,如果您听说过不可变性,请理解它与最终不同

答案 2 :(得分:0)

看起来OneValueCache类的意图是不可变的,因此将值声明为final是保证在稍后阶段程序员不会尝试扩展类并覆盖值。