2 a72880526 a72880526 于 2016.04.13 19:49 提问

java并发多线程 关于final和Volatile 的问题

@Immutable
class OneValueCache {
private final BigInteger lastNumber;
private final BigInteger[] lastFactors;

/**

  • 如果在构造函数中没有使用 Arrays.copyOf()方法,那么域内不可变对象 lastFactors却能被域外代码改变
  • 那么 OneValueCache 就不是不可变的。
    */
    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);
    }
    }

@ThreadSafe
public class VolatileCachedFactorizer 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);
cache = new OneValueCache(i, factors);//声明为 volatile ,防止指令重排序,保证可见性
}
encodeIntoResponse(resp, factors);
}
}

上面两段程序是在java并发编程中看到的。没有看明白为什么必须使用final和Volatile 这两个关键字才可以保证不使用锁他也是安全的。
能不能有大神能够说一下,假如不使用final,只使用Volatile 他会发生的不安全情况,与都使用了这两个关键字的对比。
谢谢了。万分感谢,看了一晚上。
下面就是我对两个关键字的理解:
Volatile 就是本地内存不存这个变量,直接在主内存中就行读写
final修饰变量就是这个变量是不可改变的,如果是引用类型就表示一直会引用初始化那个地址的数据,如果是基本类型,就是不能修改这个类型的值

如果不正确请指证一下

2个回答

a72880526
a72880526   2016.04.13 22:08

再提一个问:
事实不可变对象为什么需要通过安全方式来发布才能确保可见性
既然他在构造完成了过后就没有其他操作来修改他了,为什么他需要安全方式来发布呢。不是应该跟不可变对象一样就行了么

shanjuzhe
shanjuzhe   2018.06.21 09:28

构造函数中的 lastFactors 赋值,以及构造方法中 都必须使用 Arrays.copyOf()
在构造函数中,如果直接使用外部传入的数组,如果外部改变数组之后,会影响内部的不变性条件。
getFactors() 方法中同理,如果直接返回 lastFactors 对象,外部改变 lastFactors ,会影响内部的不变性条件。

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐
Java多线程/并发09、浅谈volatile
在了解volatile之前,先介绍一个名词:liveness failure ,直译叫作活性失败。因为这是volatile很重要的一个应用场景:public class volatileDemo { private static boolean stopFlag; public static void main(String[] args) throws InterruptedExc
从Java内存模型理解synchronized、volatile和final关键字
你是否真正理解并会用volatile, synchronized, final进行线程间通信呢,如果你不能回答下面的几个问题,那就说明你并没有真正的理解: 1、对volatile变量的操作一定具有原子性吗?(原子操作是不需要synchronized。所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何线程切换) 2、synchronized所谓的加锁
java中final与volatile-线程安全问题
在线程安全问题中final主要体现在安全发布问题上,在这里先讲一下什么事安全发布,在《java并发编程实践》一书中有讲,不过看起来挺难懂的…. public class Holder { private int n; public Holder(int n) { this.n = n; } public void assertSanity() {
java中 static,final,transient,volatile关键字的作用
static 和final   static  静态修饰关键字,可以修饰 变量,程序块,类的方法;  当你定义一个static的变量的时候jvm会将将其分配在内存堆上,所有程序对它的引用都会指向这一个地址而不会重新分配内存; 修饰一个程序块的时候(也就是直接将代码写在static{...}中)时候,虚拟机就会优先加载静态块中代码,这主要用于系统初始化;当修饰一个类方法时候你就可以直接通过类来
如何使用 volatile, synchronized, final 进行线程间通信
原文地址:https://segmentfault.com/a/1190000004487149。感谢作者的无私分享。 你是否真正理解并会用volatile, synchronized, final进行线程间通信呢,如果你不能回答下面的几个问题,那就说明你并没有真正的理解: 对volatile变量的操作一定具有原子性吗? synchronized所谓的加锁,锁住的是什么?
重新学习一下Java中的几个关键字(final/static/volatile......)
1、 final关键字           final关键字可以修饰类,方法和变量,对于每一种修饰都有不同的意义,但目的是相同的,保持完整性防止改变。           例如,在Java中final类不可以被继承,final变量的值不可以修改,final方法不可以被重载。           在Java中,我们无法让对象被修饰为final,而只能修饰对象的引用,这意
volatile 与 final 变量
volatile
1.2Java内存模型——原子性、内存可见性、重排序、顺序一致性、volatile、锁、final
一、原子性原子性操作指相应的操作是单一不可分割的操作。例如,对int变量count执行count++d操作就不是原子性操作。因为count++实际上可以分解为3个操作:(1)读取变量count的当前值;(2)拿count的当前值和1做加法运算;(3)将加完后的值赋给count变量。在多线程环境中,非原子操作可能会受其他线程的干扰。比如,上述例子如果没有对相应的代码进行同步(Synchronizat...
1-2 (JVM)Java内存模型---内存可见性、重排序、顺序一致性、volatile、锁、final
一、原子性原子性操作指相应的操作是单一不可分割的操作。例如,对int变量count执行count++d操作就不是原子性操作。因为count++实际上可以分解为3个操作:(1)读取变量count的当前值;(2)拿count的当前值和1做加法运算;(3)将加完后的值赋给count变量。在多线程环境中,非原子操作可能会受其他线程的干扰。比如,上述例子如果没有对相应的代码进行同步(Synchronizat...
谈谈Serializable、transient、volatile、final在多线程编程中的应用
一个实现Serializable的类的对象才可以序列化,实现序列号的对象可以以数据流的形式传输。Serializable接口中没有任何的方法。当一个类声明要实现Serializable接口时,只是表明该类参加序列化协议。 java.io包中,提供了ObjectInputStream和ObjectOutputStream将数据流功能扩展至可读写对象 。在ObjectInputStream中用rea