好的,为了好玩,我现在正在用Java练习多线程和网络,但我遇到了一些非常奇怪的事情。我有我的代码结构如下。客户端和服务器是线程,其中包含PacketListeners,它们也是在收到数据包时将数据包添加到ConcurrentLinkedQueue的线程。
我的服务器类看起来像这样
public Server(int port) {
setThreadName("ServerThread");
this.clients = new ArrayList<SocketAddress>();
try {
//this.socket = new DatagramSocket(null);
//this.socket.setReuseAddress(true);
//this.socket.bind(new InetSocketAddress(port));
//this.socket.setReuseAddress(true);
//this.socket.bind(new InetSocketAddress(port));
//sender = new PacketSender(socket);
this.listener = new PacketListener(port);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
listener.start();
}
synchronized private void processPacket(DatagramPacket packet) {
if (packet != null) {
String data = new String(packet.getData(), 0, packet.getLength());
System.out.println("Received a packet " + data);
if (data.equalsIgnoreCase("connecting")) {
System.out.println("wut");
} else {
System.out.println("Packet from :" + packet.getAddress().toString() + " saying: " + data);
}
} else {
System.out.println("Packet == null");
}
}
@Override
public void run() {
System.out.println("running server on port " + socket.getLocalPort());
while (isRunning()) {
if (listener.hasPacket()) {
System.out.println("listener has a packet");
processPacket(listener.getNextPacket());
}
sleep(1); // sleep for 1ms (keeps cpu usage from sky rocketing)
}
}
我的PacketListener类看起来像这样
public PacketListener(int port) throws IOException {
this.socket = new DatagramSocket(null);
this.socket.setReuseAddress(true);
this.socket.bind(new InetSocketAddress(port));
System.out.println("Packet listener bound @ " + socket.getLocalAddress() + " on port " + socket.getLocalPort());
receivedPackets = new ConcurrentLinkedQueue<DatagramPacket>();
}
synchronized private void addPacket(DatagramPacket packet) {
if (!receivedPackets.add(packet)) {
System.err.println("We dropped a packet because full queue");
} else {
System.out.println("We added a received packet! - " + receivedPackets.size());
}
}
synchronized public boolean hasPacket() {
return !receivedPackets.isEmpty();
}
synchronized public DatagramPacket getNextPacket() {
return receivedPackets.poll();
}
@Override
public void run() {
byte[] buffer = new byte[256];
DatagramPacket inPacket = new DatagramPacket(buffer, buffer.length);
while (isRunning()) {
try {
socket.receive(inPacket);
addPacket(inPacket);
} catch (Exception e) {
e.printStackTrace();
}
}
}
现在奇怪的是,在客户端,我说发送一些数据包。 让我们说我发送&#34;你好&#34;,然后&#34; test1&#34;,然后&#34; test2&#34; 服务器将打印出来
Packet received
We added a received packet! - 1
listener has a packet
Packet received
Received a packet test1
We added a received packet! - 1
Packet from :/127.0.0.1 saying: test1
listener has a packet
Packet received
Received a packet test2
We added a received packet! - 1
Packet from :/127.0.0.1 saying: test2
listener has a packet
这实际上应该打印出
的内容We added a received packet! - 1
listener has a packet
Received a packet hello
Packet from :/127.0.0.1 saying: hello
We added a received packet! - 1
listener has a packet
Received a packet test1
Packet from :/127.0.0.1 saying: test1
We added a received packet! - 1
listener has a packet
Received a packet test2
Packet from :/127.0.0.1 saying: test2
答案 0 :(得分:3)
我认为问题是您一遍又一遍地重复使用相同的DatagramPack实例。
这意味着一个线程接收数据包,但实际上它只是始终&#34;更新&#34; DatagramPacket的相同实例。该队列将包含相同的实例几次。
然后第二个线程从队列中拉出相同的实例,该实例在执行各种打印时发生变化,因此打印结果不稳定。
此外,我不知道DatagramPacket类的内部,但内部同步锁可能导致一个线程等待其他类似的东西。
为了确保两个线程之间没有变异的东西,我会写:
while (isRunning()) {
try {
byte[] buffer = new byte[256];
DatagramPacket inPacket = new DatagramPacket(buffer, buffer.length);
socket.receive(inPacket);
addPacket(inPacket);
} catch (Exception e) {
e.printStackTrace();
}
}