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.