Java Reference
In-Depth Information
rereading the state then. At that time, we also check to see whether the Player object has been
changed in any way (assuming that any object that mutates the state will change the altered
field from false to true). If any change has occurred, we open up the file for writing and write
the new state. We wait until the finalizer to do this to ensure that we don't waste any writes to
the file before the program is finished with the object.
This approach has a nice symmetry; what gets done in the constructor gets undone in the fi-
nalizer, and in between, things should be fast and straightforward. But the approach contains
two errors that will cause real problems. One of these errors is fairly obvious and will prob-
ably bite the program early (and often), and thus be relatively easy to deal with. The other is
subtler, and causes the kinds of errors that are hard to understand because they seem to happen
randomly.
The simpler of the two errors involves keeping the ObjectInputStream open from the cre-
ation of the Player object until that object is finalized. This ties the life cycle of the Ob-
jectInputStream to the overall life cycle of the object, and merges the resource manage-
ment of the stream with the memory management for the object. The problem with this is
that an open ObjectInputStream takes up resources other than memory. In particular, an Ob-
jectInputStream built from a FileInputStream keeps a file open, which takes up a file
descriptor. These descriptors are themselves a finite resource. Depending on the operating sys-
tem on which the virtual machine is running, you might have a lot of file descriptors, or you
might have a much smaller number. On a modern computer, the number of file descriptors
is certainly much smaller than the amount of memory available. So tying the management of
file descriptors to the management of memory is connecting the management of a scarce re-
source with the management of a much less scarce resource. More importantly, the number
of available file descriptors is almost certainly smaller than the number of players for whom
we are keeping statistics. As the number of Player objects increases, you will run out of file
descriptors, and the program written in the style shown earlier will fail.
Fixing this problem is straightforward. We simply need to move the code that closes the Ob-
jectInputStream out of the finalizer and put it back in the constructor. Rather than leaving
the ObjectInputStream open during the time that the Player object exists, we will leave
it open only when we are actively reading the contents of the stream. If we need to reread
the object, we will open the stream again. Although this might take some time, it is much
less error-prone than keeping the stream open during the entire program. By closing the Ob-
jectInputStream when we are finished using it, we explicitly manage the resource of the
file descriptors, freeing them up as soon as we no longer need them. We can also simplify
our private data structure that we use to keep track of the state of the Player . We no longer
Search WWH ::




Custom Search