ject is a good way to avoid synchronization bottlenecks, since only one thread can ever use
However, that synchronization problem would have been solved just as easily if the ex-
amples had simply created a new instance of the Random class each time one was needed.
Solving the synchronization problem that way would not have helped the overall perform-
ance, though: it is quite expensive to initialize a Random object, and continually creating in-
stances of that class would have had worse performance than the synchronization bottleneck
from many threads sharing one instance of the class.
Better performance comes from using the ThreadLocalRandom class, as is shown in
Table 7-4 . This example uses the batching stock application, and either creates a new in-
stance of a Random object or reuses a ThreadLocalRandom for each stock.
Table 7-4. Effect of ThreadLocalRandom on stock calculations
Number of stocks Allocate new Random Reuse ThreadLocalRandom
The lesson here—and in general for object reuse—is that when initialization of objects takes
a long time, don't be afraid to explore object pooling or thread-local variables to reuse those
expensive-to-create objects. As always, though, strike a balance: large object pools of gener-
ic classes will most certainly lead to more performance issues than they solve. Leave these
techniques to classes that are expensive to initialize, and when the number of the reused ob-
jects will be small.