问题描述
在以下代码中(复制自实践中的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);
}
}
为什么要克隆factors
,lastFactors
数组?不能简单地写为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;
,则factors
和lastFactors
都指向同一对象,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;
.
- servlet服务器接收请求A,执行整个
service
方法,现在lastNumber
是10
,lastFactors
是[1, 2, 5, 10]
. - servlet服务器同时接收请求B和C,首先处理了请求B,但在退出第一个
synchronized
块后(现在对于请求B,factors
是[1, 2, 5, 10]
,这是正确的),处理请求C. - 对于请求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]
.
- servlet server receives request A, the entire
service
method is executed, nowlastNumber
is10
,lastFactors
is[1, 2, 5, 10]
. - 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. - for request C, the entire
service
method is executed, it changelastFactors
from[1, 2, 5, 10]
to[1, 2, 4, 5, 10, 20]
, because bothfactors
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)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!