Java 并发实践 : Listing 3. 12 和 3.13

标签 java multithreading concurrency

我们有这些对象:

// list 3.12

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

// list 3.13

@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);
        }
        encodeIntoResponse(resp, factors);
    }
}

书上说VolatileCachedFactorizer是线程保存的。为什么?

例如:

  1. 线程A读取cache.getFactors(i);
  2. 然后线程B读取cache.getFactors(i);
  3. 然后线程B写入缓存。
  4. 然后线程A写入缓存。

这个流程可以算线程保存吗?我有什么不明白的?

最佳答案

简答:

线程安全并不是真的绝对。您必须确定所需的行为,然后询问实现是否为您提供在多线程存在的情况下的行为。

更长的答案:

那么,这里需要的行为是什么?只是总是给出正确的答案,还是如果两个线程连续请求它总是恰好执行一次?

如果是后者——也就是说,如果你真的想节省 CPU 的每一位——那么你是对的,这不是线程安全的。两个请求可以同时进入(或足够接近)以获得相同数字 N 的因式,如果计时成功,两个线程最终都可以计算出该数字。

但是对于单值缓存,您已经遇到了重新计算已知事物的问题。例如,如果收到三个请求,分别是 N、K 和 N,会怎样?对 K 的请求会使 N 处的缓存失效,因此您必须重新计算它。

因此,此缓存确实针对相同值的“连续”进行了优化,因此两次计算该连续中的前几个(甚至几个!)答案的成本可能是可以接受的成本:作为返回,您将获得没有任何阻塞且非常易于理解的代码。

重要的是它永远不会给您错误的答案。也就是说,如果您同时请求 N 和 K,则 K 的响应永远不会为您提供 N 的答案。此实现为您提供了保证,因此我将其称为线程安全。

关于Java 并发实践 : Listing 3. 12 和 3.13,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32531621/

相关文章:

.net - 在单独的进程中运行 .net 代码

c++ - 什么时候可以安全地从compare_exchange中删除memory_order_acquire或memory_order_release?

java - 如何使用 clp-java 解决简单的线性问题

java - hadoop jar 忽略指定的主类

java - 在集群 OpenText CS/AS 服务器环境上调用用户验证时出错

.net - 编码/设计通用线程安全限制器(即每秒将 X() 的执行限制为 Y 多次)

java - 是否可以从 Servlet 填充下拉列表(在 HTML/JSP 中)?

java - 关于ConcurrentLinkedQueue

c# - GUI在获取数据时未响应

java - 使用按钮启动和停止线程