I am trying to plug some shameful gaps in my Java threading knowledge, and I'm reading Java Concurrency in Practice by Brian Goetz et al (highly recommended BTW), and one of the early examples in the book leaves me with a question. In the following code, I totally understand why synchronization is needed when updating the hits and cacheHits member variables, but why is it needed for the getHits method when just reading the hits variable?
Example code from chapter 2:
public class CachedFactorizer extends GenericServlet implements Servlet {
private BigInteger lastNumber;
private BigInteger[] lastFactors;
private long hits;
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);
}...
I have a feeling it is to do with atomicity, monitors and locks, but I don't fully understand those, so please could someone out there explain a little deeper?
Thanks in advance...
James
Apart from the fact that a thread's cache view of non-volatile variables may stay non-updated indefinitely when there is no synchronization:
read/write access to a long or double is NOT guaranteed to be atomic!
You could theoretically end up seeing a value where only the first or last 4 bytes are updated. However, volatile solves this problem as well.
Because otherwise you may see a stale value of hits. Volatile would have also worked. This is relevant http://www.ibm.com/developerworks/java/library/j-jtp04186/index.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With