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中也提到了”-你能不能