ObjectInputStream 读线程阻塞 ObjectOutputStream 写线程
ObjectInputStream read thread is blocking ObjectOutputStream writing thread
我有两个线程,我们称它们为 A
和 B
。 A
不断地通过 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 对象的一部分,并且同步方法阻止了当前对该对象的访问,因此读写之间的死锁正是我所期望的。
根据您的问题 - 听起来您真正想要的是有两个单独的同步 - 一个用于输入流,一个用于输出流。如果是这种情况,我建议使用 synchronized statements。下面的示例显示了如何修改 readPacket。
public Packet readPacket() throws IOException, ClassNotFoundException{
synchronized(this.input_stream) {
return (Packet)this.input_stream.readObject();
}
}
如果你采用这种方法(让流本身成为锁),你应该将“input_stream”变量设置为 final
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 方法。
我有两个线程,我们称它们为 A
和 B
。 A
不断地通过 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 关键字,因此您已经创建了同步方法。如本
根据您的问题 - 听起来您真正想要的是有两个单独的同步 - 一个用于输入流,一个用于输出流。如果是这种情况,我建议使用 synchronized statements。下面的示例显示了如何修改 readPacket。
public Packet readPacket() throws IOException, ClassNotFoundException{
synchronized(this.input_stream) {
return (Packet)this.input_stream.readObject();
}
}
如果你采用这种方法(让流本身成为锁),你应该将“input_stream”变量设置为 final
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 方法。