创建ObjectInputStream时线程挂起

时间:2014-02-18 19:55:40

标签: java stream

我的服务器结尾处有以下代码:

public class ClientThread extends Thread
{
Socket clientSocket;

DataInputStream dis;
ObjectInputStream ois;
DataOutputStream dos;

public ClientThread(Socket acceptedSocket)
{
    clientSocket = acceptedSocket;

    try
    {
        dis = new DataInputStream(clientSocket.getInputStream());
        ois = new ObjectInputStream(clientSocket.getInputStream()); // HANGS HERE
        dos = new DataOutputStream(clientSocket.getOutputStream());
    }
    catch (Exception e)
    {
        System.out.println("ClientThread " + e.getMessage());
    }
}   

课程的其余部分省略

为什么我的应用程序在调用套接字输入流两次时会冻结,而不会抛出异常?

是的,我可以将输入流保存到InputStream变量并使用该变量来获取所需的输入流类型,但我很好奇为什么它在从套接字调用两次时会挂起?

有什么区别?被叫两次并没有改变什么?


编辑:即使将输入流保存到InputStream变量并使用该变量来获取所需的输入流(DataInputStream和ObjectInputStream),它仍会在多次调用时挂起?

示例:

public class ClientThread extends Thread
{
Socket clientSocket;

InputStream is;
DataInputStream dis;
ObjectInputStream ois;
DataOutputStream dos;

public ClientThread(Socket acceptedSocket)
{
    clientSocket = acceptedSocket;

    try
    {
        is = clientSocket.getInputStream();
        dis = new DataInputStream(is);
        ois = new ObjectInputStream(is); // STILL HANGS HERE
        dos = new DataOutputStream(clientSocket.getOutputStream());
    }
    catch (Exception e)
    {
        System.out.println("ClientThread " + e.getMessage());
    }
}   

课程的其余部分省略


客户端代码

public class LoginLogic_Callable implements Callable<String>
{
Socket socket;
String actionString;
String username;
String password;

public LoginLogic_Callable(Socket sentSocket, String sentUsername, String sentPassword)
{
    socket = sentSocket;
    username = sentUsername;
    password = sentPassword;
}

@Override
public String call() throws Exception 
{
    String userLoginStatus = null;

    try
    {
        DataOutputStream loginUserData = new DataOutputStream(socket.getOutputStream()); 
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
        DataInputStream dis = new DataInputStream(socket.getInputStream());

        String[] loginUserInfo = new String[2];

        loginUserInfo[0] = username;
        loginUserInfo[1] = password;

        loginUserData.writeUTF("userlogin");
        oos.writeObject(loginUserInfo);
        loginUserData.flush();
        oos.flush();

        userLoginStatus = dis.readUTF();

        loginUserData.close();
        oos.close();
        dis.close();
    }
    catch (Exception e)
    {
    }   

    return userLoginStatus;
}
}

1 个答案:

答案 0 :(得分:2)

只是调用getInputStream()不是'正在阅读',它不会导致此问题。您可以通过调用它十次,或者构造十次DataInputStreams来证明它。导致问题的是ObjectInputStream的构造,您可以通过完全删除DataInputStream来证明 ,无论如何都应该这样做:见下文。

您正在创建ObjectInputStreamObjectInputStream的构造函数读取由ObjectOutputStream的构造函数写入的流标头。由于这在代码中没有发生,并且可能不在同行中,它会永远阻止。

出于同样的原因,您必须先在ObjectOutputStream之前创建ObjectInputStream,否则您将再次陷入僵局。

这里似乎有一些计划在同一个套接字上使用两种流。不要那样做。它不起作用,并且没有必要,因为除了对象读写方法之外,对象流具有与数据流相同的所有方法。

编辑既然您已发布了客户端代码,那么客户端正在推迟创建ObjectOutputStream,直到调用call()为止。它应该在该类的构造函数中创建。否则,服务器端构造函数会阻塞,直到客户端调用call()为止。你仍然需要摆脱多余的流。