Thread Safety
The
LittleEndianInputStream
class
is not perfectly thread-safe. Consider the
readInt()
method:
public int readInt() throws IOException { int byte1 = in.read(); int byte2 = in.read(); int byte3 = in.read(); int byte4 = in.read(); if (byte4 == -1 || byte3 == -1 || byte2 == -1 || byte1 == -1) { throw new EOFException(); } return (byte4 << 24) + (byte3 << 16) + (byte2 << 8) + byte1; }
If two threads are trying to read from this input stream at the same time, there is no guarantee that bytes 1 through 4 will be read in order. The first thread might read bytes 1 and 2, then the second thread could preempt it and read any number of bytes. When the first thread regained control, it would no longer be able to read bytes 3 and 4, but would read whichever bytes happened to be next in line. It would then return an erroneous result.
A synchronized block would solve this problem neatly:
public int readInt() throws IOException { int byte1, byte2, byte3, byte4; synchronized (this) { byte1 = in.read(); byte2 = in.read(); byte3 = in.read(); byte4 = in.read(); } if (byte4 == -1 || byte3 == -1 || byte2 == -1 || byte1 == -1) { throw new EOFException(); } return (byte4 << 24) + (byte3 << 16) + (byte2 << 8) + byte1; }
It isn’t necessary to synchronize the entire method, only the four lines that read from the underlying stream. However, this solution is still imperfect. It is remotely possible that another thread has a reference to the underlying stream rather than the little-endian input stream ...
Get Java I/O now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.