是否有必要将读取同步到变量?

时间:2017-03-13 05:20:43

标签: java concurrency

我正在经历Java Concurrency in Practice。有些人可以解释一下我在清单2.8中的代码中遇到的以下疑问,如下所示: -

@ThreadSafe
public class CachedFactorizer implements Servlet {
    @GuardedBy("this") private BigInteger lastNumber;
    @GuardedBy("this") private BigInteger[] lastFactors;
    @GuardedBy("this") private long hits;
    @GuardedBy("this") private long cacheHits;
    public synchronized long getHits() { return hits; }
    public synchronized double getCacheHitRatio() {
        return (double) cacheHits / (double) hits;
    }
    public void service(ServletRequest req, ServletResponse resp) {
        BigInteger i = extractFromRequest(req);
        BigInteger[] factors = null;
        synchronized (this) {
            ++hits;
            if (i.equals(lastNumber)) {
                ++cacheHits;
                factors = lastFactors.clone();
            }
        }
        if (factors == null) {
            factors = factor(i);
            synchronized (this)  {
                lastNumber = i;
                lastFactors = factors.clone();
            }
}
        encodeIntoResponse(resp, factors);
    }
}
  1. getCacheHitRatio方法是否需要同步,因为cacheHitshits的更新来自同步块,而getCacheHitRatio只是读取值?
  2. 为什么在clonelastFactors中使用了factors?我不能只使用factors=lastFactors吗?这一点在本章没有解释。

1 个答案:

答案 0 :(得分:1)

1)写作方面的synchronized仅保证

1.1进入代码块后,synchronized之前的所有操作都完成并写入主存储器。

1.2块中操作的所有变量都直接来自主存储器(即刷新所有缓存行)。

1.3在块结束时,更改的变量在退出块之前写入主存储器。

因此,当您从另一个线程读取时,您需要synchronized以确保它从主内存中读取最新值,而不是从线程缓存值中读取(即CPU缓存行在使用前已成功刷新)。

2)我不知道是什么因素,但我猜这是一个共享的对象。如果是这样,Java中的赋值运算符只是指针赋值,即你仍然指向相同的因子对象;因此对其进行操作(读取和写入)仍然需要同步。