Java Reference
In-Depth Information
atBats++;
}
This method looks like it can survive being called by multiple threads at the same time. It is
just incrementing some counters, so the order in which it is called by two different threads
won't matter. Indeed, it doesn't matter if one thread increments the
hits
counter, then anoth-
er thread increments that counter and the
atBats
counter, and then the first increments the
atBats
counter. Even though there is an interweaving of the instructions, the results are the
same.
So we seem to be OK, except that we have made two assumptions that, if they are not true,
will cause us trouble. The first assumption is that the implementation of the
Batter
interface
that we get when we call
asBatter()
on a
Player
object will in fact be a
BatterImpl
. We
could check this (using a call to
instanceof
), but that defeats the idea of using an interface
as the return value of the call
asBatter()
. That idea is to allow alternate implementations of
the interface. But if we are allowing alternate implementations, we can't decide on the safety
of our system through inspection of one of the implementations, unless we have specified the
concurrency behavior as part of the interface (which we have not).
The second assumption is somewhat subtler, but can lead to just as much trouble. Even if we
have the implementation shown earlier, we have to assume that the increment operations are
atomic if we are going to avoid worry about multithreading. That is, we have to assume that
an operation like
atBats++
happens without interruption. But that is going to depend on how
the virtual machine is implemented. All we know is that an operation like
atBats++
is equi-
valent to the series of operations:
temp = atBats;
temp = temp + 1;
atBats = temp;
To see why this is a problem in an environment with multiple threads, consider the schedule
where thread 1 comes in, sets
temp
to the value in
atBats
, increments the value of
temp
by 1,
and then is stopped for some reason. Thread 2 then executes the entire sequence, starting by
setting the value of
temp
to the current value of
atBats
. Thread 1 then begins again, assigning
the value of
temp
to
atBats
. The effect of this schedule is to increment
atBats
by 1. But the
correct result is to increment it by 2.