为什么我的Java线程不能同时运行?

时间:2015-12-15 19:35:31

标签: java multithreading sockets

我有一个与UDP服务器通信的应用程序。我的应用程序侦听一个端口(比如1234)并发送另一个端口(比如5678)。我正在与之通信的UDP服务器也需要5秒钟的“心跳”,我为此创建了另一个线程。当我的应用程序首次启动时,我创建了监听线程,然后创建心跳线程,然后我开始发送UDP服务器消息包。但唯一的一点是,在心跳线程开始之前,我发出的所有数据包似乎都已完成。

以下是我对听众的看法:

public class MyListener implements Runnable {
    private volatile boolean run = true;
    private DatagramSocket myDatagramSocket;
    private DatagramPacket myDatagramPacket;
    private byte[] receiveBuffer;
    private int receiveBufferSize;

    @Override
    public void run(){
        while(run){
            try {
                myDatagramSocket = new DatagramSocket(null);
                InetSocketAddress myInetSocketAddress = new InetSocketAddress(1234);
                myDatagramSocket.bind(myInetSocketAddress);

                receiveBuffer = new byte[2047];
                myDatagramPacket = new DatagramPacket(receiveBuffer, 2047);

                myDatagramSocket.receive(myDatagramPacket);
                byte[] data = myDatagramPacket.getData();

                receiveBufferSize = myDatagramPacket.getLength();

                switch(messageID){
                    ...
                }
            } catch (Exception e){
            }
        }
    }
}

这就是我的心跳:

public class MyHeartbeat implements Runnable {
    private volatile boolean run = true;
    private HeartbeatSenderClass heartbeatSender;

    @Override
    public void run(){
        while(run){
            try {
                TimeUnit.SECONDS.sleep(5);
                heartbeatSender.sendHeartbeat();
            } catch(Exception e){
            }
        }
    }
}

以下是我主要课程的内容:

public class MyApp {
    public static void main(String[] args){
        MyListener listener = new MyListener();
        Thread listenerThread = new Thread(listener);
        listenerThread.setName("Listener Thread");
        listenerThread.start();

        MyHeartbeat heartbeat = new MyHeartbeat();
        Thread heartbeatThread = new Thread(heartbeat);
        heartbeatThread.setName("Heartbeat Thread");
        heartbeatThread.start();

        MySender sender = new MySender();
        Thread senderThread = new Thread(sender);
        senderThread.setName("Sender Thread");
        senderThread.start();
    }
}

我的所有数据包都在进入UDP服务器,但并不像我想象的那样顺利。我会想到,当我向服务器发送数据包时,每5秒我的心跳就会被发送出去。但是,似乎我的心跳只在我的数据包发送完毕后才会出现。另外,我相信我没有从UDP服务器获取所有消息。我这样说是因为我在我的机器上嗅到了UDP数据包,而且我看到来自服务器的数据是我的接收器没有接收/处理的。有什么建议吗?

2 个答案:

答案 0 :(得分:1)

你心跳加速:

 TimeUnit.SECONDS.sleep(5);
 heartbeatSender.sendHeartbeat();

所以在发送第一个节拍之前,你等待5秒钟。难怪其他线程同时完成它们的工作。

答案 1 :(得分:0)

用于发送数据包的DatagramSocket是一个在线程之间竞争的共享资源,然后如果一个线程消耗了太多的资源,另一个可能会饿死。请参阅:Thread starvation

此外,如果您丢失数据包,则会发生这种情况,因为您无法以尽可能快的速度阅读。如果udp数据包到达速度更快,则可以读取它们,队列将丢弃剩余的数据包。

在linux下,您可以使用以下命令控制接收缓冲区:

sudo sysctl -w net.core.rmem_default=26214400
sudo sysctl -w net.ipv4.udp_mem='26214400 26214400 26214400'
sudo sysctl -w net.ipv4.udp_rmem_min=26214400

但无论如何,如果我们谈论持续的损失,你应该考虑让一个线程来读取缓冲区,一个队列和一个线程来处理这些已知的数据。