Java 易变vs决赛。这里的final有什么用
下面是实践中并发的代码片段Java 易变vs决赛。这里的final有什么用,java,Java,下面是实践中并发的代码片段 class OneValueCache { private final BigInteger lastNumber; private final BigInteger[] lastFactors; public OneValueCache(BigInteger i,BigInteger[] factors) { lastNumber = i; lastFactors = Arrays.copyOf(factors, fact
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 cache”确保对象对所有其他线程可见,我假设volatile write之前的写入对所有其他线程可见。它们是两个不同的东西。 一般来说
volatile
-->创建内存屏障,强制刷新缓存中的数据,并强制从主存读取数据。因此,所有线程都可以获得这个特定字段的更新数据
最终版
-->
最后和不变性是两个不同的概念。所以,如果你听说过不变性,请理解它不同于final。它们是两个不同的东西。 一般来说
volatile
-->创建内存屏障,强制刷新缓存中的数据,并强制从主存读取数据。因此,所有线程都可以获得这个特定字段的更新数据
最终版
-->
最后和不变性是两个不同的概念。因此,如果您听说过不变性,请理解它与final不同。看起来OneValueCache类的意图是不可变的,因此将值声明为final只会确保程序员在稍后的某个阶段不会尝试扩展该类并覆盖这些值 看起来OneValueCache类的目的是不可变的,因此将值声明为final可以保证程序员在以后的某个阶段不会尝试扩展该类并覆盖这些值 最终字段使OneValueCache不可变,从而使其线程安全。它们还具有由定义的特殊语义,特别是,任何线程都能够看到正确构造的对象,并将最终字段初始化为其唯一正确的值 如果情况并非如此,并且字段恰好不是最终字段,那么其他线程可能无法看到更改,甚至在构造函数中也无法看到更改,因为没有最终字段,就没有构造安全保证
JCIP解释说OneValueCache只是一个用于保存两位数据的不可变引用类。这比更新方法中的两个字段更安全,因为它不是原子的。然后,OneValueCache在servlet中变得不稳定,因为它需要更改,但它是一个原子赋值,因此不需要同步 最终字段使OneValueCache不可变,从而使其线程安全。它们还具有由定义的特殊语义,特别是,任何线程都能够看到正确构造的对象,并将最终字段初始化为其唯一正确的值 如果情况并非如此,并且字段恰好不是最终字段,那么其他线程可能无法看到更改,甚至在构造函数中也无法看到更改,因为没有最终字段,就没有构造安全保证
JCIP解释说OneValueCache只是一个用于保存两位数据的不可变引用类。这比更新方法中的两个字段更安全,因为它不是原子的。然后,OneValueCache在servlet中变得不稳定,因为它需要更改,但它是一个原子赋值,因此不需要同步 +1对于final上的线程安全性,太多的人忘记了它。根据惯例,将任何字段都设为final:)它提到“编写一个易失性变量就像退出一个同步块”。如果是这种情况,OneValueCache构造函数中的写入不会相对于Volatile write重新排序,并且Volatile write之前的写入对所有其他线程都可见。因此,即使不使用final,它仍然有效?关键是使OneValueCache不可变。理论上,是的,OneValueCache的构造发生在volatile
缓存的分配之前,这发生在读取另一个线程之前,以确保可见性,但您不应该依赖于此,因为它非常脆弱,应该留给那些确切知道自己在做什么的人(顺便说一句,JCIP中也提到了)谢谢你的解释。“顺便说一句,JCIP中也提到了”-你能给我指一下这个链接吗?+1对于final上的线程安全,太多人忘记了它。它也碰巧是按照惯例,使任何字段都可能成为final:)它提到“编写一个volatile变量就像退出一个同步块”。如果是这种情况,OneValueCache构造函数中的写入不会相对于Volatile write重新排序,并且Volatile write之前的写入对所有其他线程都可见。因此,即使不使用final,它仍然有效?关键是使OneValueCache不可变。理论上,是的,OneValueCache的构造发生在volatile缓存的分配之前,这发生在读取另一个线程之前,以确保可见性,但您不应该依赖于此,因为它非常脆弱,应该留给那些确切知道自己在做什么的人(顺便说一句,JCIP中也提到了)谢谢你的解释。“顺便提一下,JCIP中也提到了”-你能不能