Why does order of instantiation seem to matter for input and output streams in Java?

664 views Asked by At

I have the following code that works (please assume that hostname and port are initialized to their proper values, and that Message is a serializable class):

//Example 1 - everything works as expected
Message message = new Message();
try(Socket serverSocket = new Socket(hostname, port))
{
    ObjectOutputStream outStream = new ObjectOutputStream(serverSocket.getOutputStream());                  
    outStream.writeObject(message);
    outStream.flush();

    ObjectInputStream inStream = new ObjectInputStream(serverSocket.getInputStream());
    Object response = inStream.readObject();
}

When I move the instantiation of the ObjectInputStream to occur immediately after the ObjectOutputStream instantiation, execution of my application hangs indefinitely:

//Example 2 - client locks up
Message message = new Message();
try(Socket serverSocket = new Socket(hostname, port))
{
    ObjectOutputStream outStream = new ObjectOutputStream(serverSocket.getOutputStream());                  
    ObjectInputStream inStream = new ObjectInputStream(serverSocket.getInputStream());

    outStream.writeObject(message);
    outStream.flush();

    Object response = inStream.readObject();
}

I'm looking for a good explanation as to why the second example locks up consistently, and the first example seems to work without a hitch. Strangely, if I use a debugger (Eclipse debugger) on the client and server with this second example, I'm seeing the message make it through to the server, so the writeObject() call is being executed. However, in the client, the debugger gets stuck on the constructor for the ObjectInputStream.

2

There are 2 answers

0
display101 On BEST ANSWER

If we go and have a read of the API docs for the ObjectInputStream constructor

The important part:

This constructor will block until the corresponding ObjectOutputStream has written and flushed the header.

0
user207421 On

Constructing an ObjectOutputStream writes a header to the stream. Constructing an ObjectInputStream reads it. If both ends construct the ObjectInputStream first, you will therefore get a deadlock.

Solution: construct the ObjectOutputStream first, at both ends, to make sure it can't happen.