Java 创建ObjectInputStream时线程挂起

Java 创建ObjectInputStream时线程挂起,java,stream,Java,Stream,我的服务器上有以下代码: public class ClientThread extends Thread { Socket clientSocket; DataInputStream dis; ObjectInputStream ois; DataOutputStream dos; public ClientThread(Socket acceptedSocket) { clientSocket = acceptedSocket; try { di

我的服务器上有以下代码:

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());
    }
}   
省略了班上的其他部分

为什么我的应用程序在两次调用socket inputstream而不引发异常时会冻结

是的,我可以将inputstream保存到一个inputstream变量中,并使用该变量来获得所需的inputstream类型,但我很好奇,当从套接字调用两次时,为什么它会挂起

有什么区别?被叫两次也不会改变什么


编辑:即使将inputstream保存到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;
}
}
公共类LoginLogic\u Callable实现可调用
{
插座;
字符串actionString;
字符串用户名;
字符串密码;
公共LoginLogic_可调用(套接字sentSocket、字符串sentUsername、字符串sentPassword)
{
插座=插座;
用户名=用户名;
密码=密码;
}
@凌驾
公共字符串调用()引发异常
{
字符串userLoginStatus=null;
尝试
{
DataOutputStream loginUserData=新的DataOutputStream(socket.getOutputStream());
ObjectOutputStream oos=新的ObjectOutputStream(socket.getOutputStream());
DataInputStream dis=新的DataInputStream(socket.getInputStream());
String[]loginUserInfo=新字符串[2];
loginUserInfo[0]=用户名;
loginUserInfo[1]=密码;
loginUserData.writeUTF(“用户登录”);
oos.writeObject(loginUserInfo);
loginUserData.flush();
oos.flush();
userLoginStatus=dis.readUTF();
loginUserData.close();
oos.close();
dis.close();
}
捕获(例外e)
{
}   
返回userLoginStatus;
}
}

仅调用
getInputStream()
不是“读取”,也不会导致此问题。您可以通过十次调用它,或者构造十个
DataInputStreams
来证明这一点。问题是由
ObjectInputStream
的构造引起的,您可以通过删除
DataInputStream
来证明这一点,您无论如何都应该这样做:见下文

您正在创建一个
ObjectInputStream
ObjectOutputStream
的构造函数读取由
ObjectOutputStream的构造函数编写的流头。由于这在代码中没有发生,并且可能在对等端也没有发生,所以它会永远阻塞

出于同样的原因,必须先创建
ObjectOutputStream
,然后再创建
ObjectInputStream
,否则将再次出现死锁

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


编辑现在,您已经发布了客户端代码,现在发生的情况是客户端正在推迟创建
ObjectOutputStream
,直到调用
call()
。它应该在该类的构造函数中创建。否则,服务器端构造函数将阻塞,直到在客户端调用
call()
。您仍然需要消除冗余流。

我知道在android中,东西有时会挂起,但使用asynctask可以解决这个问题。不知道java中异步任务的名称。我想这不是问题,只是一个评论。如果你编辑,你似乎没有读过我的答案。请发布相关的客户端代码。添加了客户端代码。好的,现在请查看编辑我的答案。这没有意义。。。所以你是说我必须在创建ObjectInputStream之前创建ObjectOutputStream,即使在这种情况下我永远不会使用ObjectOutputStream。@Birdman如果你永远不会使用ObjectOutputStream,那么你打算什么时候使用ObjectOutputStream?如果输出流不发送对象,则无法接收输入流中的对象。客户端(对等方)有一个ObjectOutputStream,服务器(此处就是这种情况)有一个ObjectInputStream来接收对象。那怎么了?它不仅有意义,而且在Javadoc中有文档记录。如果对等方正在创建ObjectOutputStream,那么它必须在创建ObjectInputStream之后创建,这会导致死锁,正如我前面所说的那样。@Alex,这不符合要求。您可以只向一个方向发送对象,也可以向两个方向发送对象。