ObjectInputStream读线程阻塞ObjectOutputStream写线程



我有两个线程,我们称它们为ABA通过readPacket函数不断寻找来自ObjectInputStream的数据包(这将是线程中的while(true)等)

A正在寻找这些数据包时,我希望B通过writePacket函数向ObjectOutputStream写入数据包。

但是每当我想这样做的时候,我就会进入死锁;我不明白为什么两个不同的函数会彼此死锁?

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
public class ConnectionBay
{
private Socket connection;
private ObjectOutputStream output_stream;
private ObjectInputStream input_stream;
ConnectionBay(Socket socket) throws IOException{
this.connection = socket;
this.output_stream = new ObjectOutputStream(connection.getOutputStream());
this.output_stream.flush();
this.output_stream.reset();
this.input_stream = new ObjectInputStream(connection.getInputStream());
}
public synchronized void writePacket(Packet packet) throws IOException{
this.output_stream.writeObject(packet);
this.output_stream.flush();
this.output_stream.reset();
}
public synchronized Packet readPacket() throws IOException, ClassNotFoundException{
return (Packet)this.input_stream.readObject();
}
}

由于您在readPacket和writePacket定义中使用了synchronized关键字,因此您已经创建了同步方法。如本教程所述,对同一对象的同步方法的两次调用不可能交错。在你的例子中,"对象"。不是输入或输出流,而是ConnectionBay对象。通常,当您希望防止两个线程访问对象中的任何状态时,您可以使用同步方法。因为两个流都是一个ConnectionBay对象的一部分,而同步方法阻止了当前对该对象的访问,所以读写之间的死锁正是我所期望的。

根据你的问题——听起来你真正想要的是有两个独立的同步——一个用于输入流,一个用于输出流。如果是这种情况,我建议使用同步语句。下面的例子展示了如何修改readPacket。

public Packet readPacket() throws IOException, ClassNotFoundException{
synchronized(this.input_stream) {
return (Packet)this.input_stream.readObject();
}
}

如果您采用这种方法(让流本身成为锁),您应该使用"input_stream"变量最终

private final ObjectInputStream input_stream;

这确保了您可以安全地使用input_stream作为锁,因为它保证在构造后不会更改。

另一种方法是创建另外两个变量作为锁,并将它们与流配对。

private ObjectInputStream input_stream;
private final Object input_lock = new Object();
private ObjectOutputStream output_stream;
private final Object output_lock = new Object();

public Packet readPacket() throws IOException, ClassNotFoundException{
synchronized(this.input_lock) {
return (Packet)this.input_stream.readObject();
}
}

这种方法更灵活,如果你在连接湾的生命周期内创建和销毁流变量,这种方法可能是必要的。

不要忘记用类似的更改来更新你的writePacket方法

最新更新