怀疑与易失性,不可变对象有关,以及它们用于实现同步

时间:2013-06-11 21:22:45

标签: java synchronization immutability volatile

我正在阅读“实践中的java并发”一书,并在几页之后结束了一些疑问。

1)具有非premitive数据类型的Voltile:  私人挥发学生; 当非预先数据类型出现时,volatile的重要性是什么? (我认为在这种情况下只认为所有线程都可以看到Strudent对象s当前指向的内容并且可能一个线程A修改了学生的某个内部成员,而其他线程看不到。我是对的??)

2) 变量是否可以是不可变的,即使内部成员未被声明为final? 例如:

Class  A {

    private Set<String> s = new Set();
    public A() {
        s.add("Moe");
        s.add("Larry");
        s.add("Curly");
    }
} 

在这个类中,我们是否需要使Set s final使其不可变或者这个类仍然是不可变的? (因为即使在这种情况下,我们也无法在创建对象后改变它的状态。)

3)书中有一个例子,展示如何组合使用volatile和immutable类来获得同步。在我提出这个问题之前,我还有一个疑问。 假设有这样的功能:

private Student s = new Student;

void func() {
    s.func2();      // 1
    if(s.isPossible()) { //2
        s = new Student(); //3      
    }
}

a)func2()访问s的内部成员。现在考虑在执行第1行后线程A进入func2,同时线程B用新对象重新分配s。线程A恢复时 它将使用新物体或旧物体? (假设s初始指向内存位置100(旧对象),并且在分配新对象后,它开始指向200(新对象) 然后,当线程A恢复时,它将访问地址100或地址200)。

b)如果我挥发,它会对上述情况产生任何影响。

4。)这是最后一个

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

@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); // Position A

        if (factors == null) {
            factors = factor(i);
            cache = new OneValueCache(i, factors); // Position B
        }
        encodeIntoResponse(resp, factors);
    }
}

加入书类“VolatileCachedFactorizer”是线程安全的。这是我的理由,为什么它是线程安全的(如果我错了,纠正我。)Positin A和B位置 可疑的立场。

位置A:当缓存指向不可变对象时,任何函数调用都是安全的(对吗?)。

职位B:可以有两个问题

a)线程看到缓存未正确初始化。在这种情况下不可能保证不可变对象被正确初始化(对吗?)。

b)新分配的对象对其他线程不可见。这种情况不可能,因为缓存是易失性的(对吧?)。

但是有可能是线程A调用getFactors()和其他线程B重新分配缓存,在这种情况下A会继续看旧对象(对吗?)

2 个答案:

答案 0 :(得分:2)

  1. 是; volatile仅适用于它应用的引用。

  2. 没有;碰巧被最终字段指向的对象不会神奇地变成不可变的 具有可变非公共成员的对象只有在永远不会发生变异的情况下才是不可变的。 (显然)

答案 1 :(得分:0)

在对我的所有答案进行一些测试后发现。

  1. volatile仅适用于参考。挥发性对象的任何对象点都不需要在其他线程中可见。

  2. 是的,最后很重要。没有它,类的对象将不会是不可变的。

  3. 假设当一个函数调用obj时,变量“obj”指向位置x(放置实际对象),那么在函数调用期间,所有成员变量都将从位置x读取,即使其他一些变量也是如此线程在“obj”上分配一个不同的对象。

  4. 对所有答案的假设解释都是正确的。