本文介绍了“实践中的Java并发" -缓存的线程安全数字分解器(清单2.8)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下代码中(复制自实践中的Java并发第2章,第2.5节,清单2.8):

In the following code (copied from Java Concurrency in Practice Chapter 2, section 2.5, Listing 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(); // questionable line here
            }
        }
        if (factors == null) {
            factors = factor(i);
            synchronized (this) {
                lastNumber = i;
                lastFactors = factors.clone(); // and here
            }
        }
        encodeIntoResponse(resp, factors);
    }
}

为什么要克隆factorslastFactors数组?不能简单地写为factors = lastFactors;lastFactors = factors;吗?仅仅是因为factors是局部变量,然后将其传递给encodeIntoResponse,它可以对其进行修改?

why the factors, lastFactors arrays are cloned? Can't it be simply written as factors = lastFactors; and lastFactors = factors;? Just because the factors is a local variable and it is then passed to encodeIntoResponse, which can modify it?

希望问题很明确.谢谢.

Hope the question is clear. Thanks.

推荐答案

如果将factors = lastFactors.clone();更改为factors = lastFactors;,则factorslastFactors都指向同一对象,factors更长,它将变为共享的可变状态.

If you change factors = lastFactors.clone(); to factors = lastFactors;, both factors and lastFactors point to the same object, factors is no longer a local variable, it becomes a shared mutable state.

想象一下,有三个请求,即请求A,B,C.请求A和B发送的数字为10,但是请求C发送的数字为20.如果发生以下执行顺序并且您进行了更改,则可能会出错. factors = lastFactors.clone();factors = lastFactors;.

Imagine there are three requests, request A, B, C. The number sent by Request A and B is 10, but the number sent by request C is 20. Things can go wrong if the below execution order happens and you change factors = lastFactors.clone(); to factors = lastFactors;.

  1. servlet服务器接收请求A,执行整个service方法,现在lastNumber10lastFactors[1, 2, 5, 10].
  2. servlet服务器同时接收请求B和C,首先处理了请求B,但在退出第一个synchronized块后(现在对于请求B,factors[1, 2, 5, 10],这是正确的),处理请求C.
  3. 对于请求C,将执行整个service方法,它将lastFactors[1, 2, 5, 10]更改为[1, 2, 4, 5, 10, 20] ,因为这两个factors lastFactors都指向同一个对象,factors现在也为[1, 2, 4, 5, 10, 20]. 请求B的响应应该为[1, 2, 5, 10],但现在为[1, 2, 4, 5, 10, 20] .
  1. servlet server receives request A, the entire service method is executed, now lastNumber is 10, lastFactors is [1, 2, 5, 10].
  2. servlet server receives both request B and C, request B is handled at first, but after exiting the first synchronized block (now for request B, factors is [1, 2, 5, 10], which is correct), request C is handled.
  3. for request C, the entire service method is executed, it change lastFactors from [1, 2, 5, 10] to [1, 2, 4, 5, 10, 20], because both factors lastFactors point to the same object, factors is now [1, 2, 4, 5, 10, 20] too. The response of request B is supposed to be [1, 2, 5, 10], but is [1, 2, 4, 5, 10, 20] right now.

这篇关于“实践中的Java并发" -缓存的线程安全数字分解器(清单2.8)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 22:15