Java 一个数据报接收器需要多少线程?

Java 一个数据报接收器需要多少线程?,java,multithreading,sockets,udp,datagram,Java,Multithreading,Sockets,Udp,Datagram,我为我用java(和LWJGL)创建的游戏创建了一个收发数据报系统 然而,这些数据报经常被丢弃。这是因为服务器在主循环中等待各种IO操作和其他处理完成,同时向其发送新的数据报(显然它没有监听) 为了解决这个问题,我使用while-true循环来捕获数据报,但是我没有在主线程中进行处理,而是将分支扩展到不同的线程 像这样: ArrayList<RecieveThread> threads = new ArrayList<RecieveThread>(); public vo

我为我用java(和LWJGL)创建的游戏创建了一个收发数据报系统

然而,这些数据报经常被丢弃。这是因为服务器在主循环中等待各种IO操作和其他处理完成,同时向其发送新的数据报(显然它没有监听)

为了解决这个问题,我使用while-true循环来捕获数据报,但是我没有在主线程中进行处理,而是将分支扩展到不同的线程

像这样:

ArrayList<RecieveThread> threads = new ArrayList<RecieveThread>();
public void run(){

    while (true){
        //System.out.println("Waiting!");
        byte[] data = new byte[1024];
        DatagramPacket packet = new DatagramPacket(data, data.length);
        try {
            socket.receive(packet);
        } catch (IOException e) {
            e.printStackTrace();
        }



        //System.out.println("Recieved!");
        String str = new String(packet.getData());
        str = str.trim();
        if (threads.size() < 50){
        RecieveThread thr = new RecieveThread();
        thr.packet = packet;
        thr.str = str;
        threads.add(thr);
        thr.start();
        }else{
            boolean taskProcessed = false;
            for (RecieveThread thr : threads){
                if (!thr.nextTask){
                    thr.packet = packet;
                    thr.str = str;
                    thr.nextTask = true;
                    taskProcessed = true;
                    break;
                }
            }
            if (!taskProcessed){
            System.out.println("[Warning] All threads full! Defaulting to main thread!");
            process(str, packet);
            }

        }

    }
}
ArrayList threads=new ArrayList();
公开募捐{
while(true){
//System.out.println(“等待!”);
字节[]数据=新字节[1024];
DatagramPacket数据包=新的DatagramPacket(数据,数据.长度);
试一试{
套接字接收(数据包);
}捕获(IOE异常){
e、 printStackTrace();
}
//System.out.println(“received!”);
String str=新字符串(packet.getData());
str=str.trim();
if(threads.size()<50){
ReceiveThread thr=新ReceiveThread();
thr.packet=分组;
thr.str=str;
螺纹。添加(thr);
thr.start();
}否则{
布尔值=false;
用于(接收线程数:线程数){
如果(!thr.nextTask){
thr.packet=分组;
thr.str=str;
thr.nextTask=true;
taskProcessed=true;
打破
}
}
如果(!taskProcessed){
System.out.println(“[警告]所有线程已满!默认为主线程!”);
过程(str,packet);
}
}
}
}
这就是为每个传入的数据报创建一个新线程,直到它到达50个数据包,此时它选择在一个等待下一个任务的现有线程中进行处理——如果所有线程都在处理,则默认为主线程

所以我的问题是:多少线程是一个好的数量?我不想让任何人的系统过载(同样的代码也会在玩家的客户端上运行),但我也不想增加系统的数据包丢失

另外,不同的线程是一个好主意吗?有人有更好的方法吗

编辑:这是我的ReceiveThread类(类长777行):

String-str;
数据包;
布尔值nextTask=true;
公开募捐{
while(true){
////System.out.println(“客户:+str”);
//赛前
而(!nextTask){
//没什么
}       
}
}

关于使用NginX或Apache的疑问,您似乎也遇到了同样的问题。你读过关于NginX和10k问题的书吗?如果没有,请阅读。像这样的问题没有“正确”的答案。正如其他同事所强调的,这个问题是关于应用程序环境的需求(方面)。请记住,我们有这么多的web框架:每个框架都解决了相同的问题,即服务于html文档的内容,但使用不同的方法来完成任务。

可能只有一个线程,假设您有一个
DatagramSocket。
您总是可以从读取UDPSocket的线程中生成一个processData线程。正如人们在评论中所说,这取决于你,但通常一个是好的

编辑:


如果您这样做的话,还可以查看互斥体。

首先,任何使用数据报(如UDP)进行通信的系统都必须能够处理丢弃的请求。它们会发生的。你能做的最好的事情就是将典型的下降率降低到可以接受的程度。但您还需要认识到,如果您的应用程序无法处理丢失的数据报,那么它就不应该使用数据报。改用普通插座

现在来看看要使用多少线程的问题。答案是“视情况而定”

  • 一方面,如果没有足够的线程,可能会有未使用的硬件容量(核心)在高峰时间使用。。。但事实并非如此

  • 如果一次运行(或可运行)的线程太多,它们将在不同级别争夺资源:

    • CPU竞争
    • 内存带宽竞争
    • 锁和共享内存上的争用
    所有这些因素(以及相关的二阶效应)都会降低吞吐量。。。相对于最优。。。如果你有太多的线程

  • 如果您的请求处理涉及到与其他机器上的数据库或服务器对话,那么您需要足够的线程来允许在等待响应时发生其他事情

根据经验,如果您的请求是独立的(共享数据上的争用最小)并且独占在内存中(没有数据库或外部服务请求),那么每个核心一个工作线程是一个很好的起点。但是你需要准备好调整(或者重新调整)这个

最后,还有处理过载的问题。一方面,如果超载情况是暂时的,那么排队是一种合理的策略。。。前提是队列不会太深。另一方面,如果您预计过载很常见,那么最好的策略是尽早删除请求

然而,还有一个次要问题。丢弃的请求可能需要客户端注意到它在给定的时间内没有收到回复,然后重新发送请求。这可能导致更严重的问题;i、 客户端在服务器实际删除请求之前重新发送请求。。。这可能导致同一请求被多次处理,并导致有效吞吐量的灾难性下降


请注意,如果线程太多,并且由于资源争用而陷入困境,也会发生同样的情况。

通常没有神奇的t数
    String str;
DatagramPacket packet;
boolean nextTask = true;
public void run(){
    while (true){
////System.out.println("CLIENT: " + str);
            //BeforeGame
        while (!nextTask){
            //Nothing
        }       
        <Insert processing code here that you neither know about, nor care to know about, nor is relevant to the issue. Still, I pastebinned it below>
    }
}