Java多线程,奇怪的事情

时间:2014-09-02 23:09:09

标签: java multithreading sockets concurrency

好的,为了好玩,我现在正在用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

1 个答案:

答案 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();
        }
    }