为什么实例化顺序似乎对 Java 中的输入和输出流很重要?

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

我有以下有效代码(请假设主机名和端口已初始化为其正确的值,并且消息是可序列化的 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();
}

当我将 ObjectInputStream 的实例化移动到 ObjectOutputStream 实例化之后立即发生时,我的应用程序的执行无限期挂起:

//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();
}

我正在寻找一个很好的解释,说明为什么第二个示例始终锁定,而第一个示例似乎运行顺利。奇怪的是,如果我在第二个示例中在客户端和服务器上使用调试器(Eclipse 调试器),我会看到消息到达服务器,因此正在执行 writeObject() 调用。但是,在客户端中,调试器卡在 ObjectInputStream.

的构造函数上

构造 ObjectOutputStream 将 header 写入流。构造一个 ObjectInputStream 读取它。如果两端都先构造ObjectInputStream,就会出现死锁。

解决方案:先在两端构造ObjectOutputStream,确保不会发生。

如果我们去阅读 API 文档 ObjectInputStream constructor

重要部分:

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