The reason to do this obviously is not for the code clarity. But these data objects are guar-
anteed to have atomic implementations of the various methods, so we can be sure that this
implementation, even without the locking provided by synchronization, will result in correct
statistics. This does not solve the problem of possibly returning an inconsistent statistic be-
cause a getRoster() call picks up a player that is in the middle of an atBat() update, but it
keeps the data from being corrupted, which is a much more serious problem.
The atomic data items are very useful when you need to implement a multithreaded counter or
need to make some comparison in a routine that might have multiple threads running through
it. There is nothing that can be done with these that can't be done with synchronized over the
right scope, but the atomic objects will probably perform better, and you don't have to think
about the scope of the lock. Atomic objects should not be overused or (as we did earlier in this
chapter) used for the wrong reasons. But when you need one of them, they can't be beat.
There are lots of other classes that can help with concurrency in Java programs. We haven't
talked about the various kinds of lock classes that can be used, or the way in which the threads
that you start can be controlled. Doing a thorough job of describing the richness of the con-
What makes the concurrency mechanisms in the Java language and environment good is not,
in general, that there is some new way of dealing with concurrency. It is still hard, and you
still have to think about it, and debugging a concurrency problem in Java is just as much a
hit-your-head-on-the-wall problem as it is in other languages. What makes Java concurrency
different is that the language and the environment have some built-in help for all of the prob-
lems. You don't have to figure out how to build your own locking mechanism; there is the
synchronized keyword. You don't have to find the right library to spawn new threads, since
threads are part of the basic environment (and are first-class entities in the language itself).
And, because threads are in the language, you don't have to figure out the different (and mind-
bogglingly complex) libraries dealing with threads on the different platforms that you need to
support; you can simply let the JVM implementation cover over those facts for you.
Concurrent programming is the next frontier for languages and software engineering. Because
of the advent of multicore systems, those of us who used to be able to ignore concurrent pro-
gramming will no longer have that option. We are going to have to understand concurrency,
and over time, we will no doubt invent idioms and practices that will make the programming
of concurrent systems easier and more stylized. Until that happens, though, it is good to have