0

我正在阅读《Java 并发实践》一书,几页后就产生了一些疑问。

1) Voltile 具有非 premitive 数据类型:私有 volatile Student s;当它带有非前置数据类型时,volatile 的意义是什么?(我认为在这种情况下,只认为所有线程都可以看到 Strudent 对象当前指向的内容,并且一个线程 A 可能修改了 student 的某些内部成员,而其他线程不可见。我是对的??)

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

Class  A {

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

在这个类中,我们需要将 Set 设为 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 的内部成员。现在考虑线程 A 在执行第 1 行后进入 func2 和线程 B 同时用新对象重新分配 s。当线程 A 恢复时,它将使用新对象还是旧对象?(假设 s 最初指向内存位置 100(旧对象),在分配新对象后,它开始指向 200(新对象),然后当线程 A 恢复时,它将访问地址 100 或地址 200)。

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

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”是线程安全的。这是我为什么它是线程安全的推理(如果我错了,请纠正我。)位置 A 和位置 B 是可疑的位置。

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

位置B:它可能有两个问题

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

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

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

4

2 回答 2

2
  1. 是的; volatile仅适用于它所应用的参考。

  2. 不; 碰巧被 final 字段指向的对象不会神奇地变得不可变。
    具有可变非公共成员的对象只有在这些成员永远不能被改变的情况下才是不可变的。(明显地)

于 2013-06-11T21:26:47.050 回答
0

经过一些测试我所有的答案后发现。

  1. volatile 仅适用于参考。volatile 对象指向的任何对象都不需要对其他线程可见。

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

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

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

于 2013-06-13T20:31:17.863 回答