Java Reference
In-Depth Information
Note
Java 8 enhances the Map interface with a method computeIfAbsent for such use cases. We
mention it in appendix B . But for your information you could use the method computeIfAbsent
as follows to write clearer code:
Integer computeNumberOfNodesUsingCache(Range range) {
return numberOfNodes.computeIfAbsent(range,
this::computeNumberOfNodes);
}
It's clear that the method computeNumberOfNodesUsingCache is referentially transparent
(assuming the method computeNumberOfNodes is also referentially transparent). But the fact
that numberOfNodes is mutable shared state, and that HashMap isn't synchronized, [ 2 ] means
that this code isn't thread-safe. Even using (lock-protected) Hashtable or
(concurrent-without-locking) ConcurrentHashMap instead of HashMap may not give the
expected performance if there are parallel calls to numberOfNodes from multiple cores, because
there's a race condition between your finding that range isn't in the map and inserting the
(argument, result) pair back into the map. This means multiple processes might compute the
same value to add to the map.
2 This is one of those places where bugs breed. It's so easy to use HashMap here and to forget the
fact that the Java manual notes that it's not thread-safe (or to simply not care because our
program is currently single-threaded).
Perhaps the best thing to take away from this struggle is that mixing mutable state with
concurrency is trickier than you'd imagine, and functional-style programming avoids it entirely,
except for low-level performance hacks such as caching. A second thing is that apart from
implementing tricks like caching, if you code in functional style, then you never need to care
whether or not another functional-style method you call is synchronized, because you know it
has no shared mutable state.
14.5.2. What does “return the same object” mean?
Let's consider again the binary tree example from section 14.2.3 . In figure 14.4 , variable t points
to an existing Tree, and the figure shows the effect of calling fupdate("Will", 26, t) to produce a
new Tree, which we'll assume is assigned to variable t2. The figure makes it clear that t, and all
Search WWH ::




Custom Search