[英]volatile vs final. What is the use of final over here
下面是实践中并发的代码片段。
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的用途是什么。 “易失性OneValueCache缓存”确保该对象对所有其他线程可见,并且我假定对易失性写入之前的所有其他线程可见该对象。
最终字段使OneValueCache不可变,从而使其成为线程安全的。 它们还具有JLS定义的特殊语义,特别是,任何线程都将能够看到将最终字段初始化为其唯一正确值的正确构造的对象。
如果不是这种情况,并且字段恰好不是final,则其他线程可能也看不到更改,即使在构造函数中也是如此,因为如果没有final字段,就无法保证构造安全。
JCIP解释说,OneValueCache只是一个不变的引用类,用于保存数据的两位。 这比更新方法中的两个字段更安全,因为它不是原子的。 然后,由于需要更改OneValueCache,因此它在servlet中变得易失,但这是一个原子分配,因此不需要同步。
他们是两个不同的东西。 通常,
volatile
>创建一个内存屏障,以强制刷新高速缓存中的数据并强制从主内存中读取数据。 因此,所有线程始终可以获取该特定字段的更新数据。
final
->
对于基元->指定该值不能更改
对于非基元->引用不能更改(即,引用不能指向另一个对象)。 为了使对象/字段不可变 ,您需要确保最终字段可传递地访问该对象/字段,并且对它的引用不会进行转义。
PS: 最终和不变性是两个不同的概念。 因此,如果您听说过不可变性,请理解它与final 有所不同 。
看起来OneValueCache类的意图是不可变的,因此将值声明为final只是为了保证程序员在以后的某个阶段不尝试扩展该类并覆盖这些值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.