【问题标题】:Optimizing a java multithreaded server that uses an inputstreamreader优化使用 inputstreamreader 的 java 多线程服务器
【发布时间】:2017-02-01 16:41:28
【问题描述】:

我目前正在做一个项目,我必须在其中托管一个服务器,该服务器获取输入流,解析数据并将其发送到数据库。每个连接到我的服务器的客户端都会发送一个输入流,一旦连接就永远不会停止。每个客户端都分配有一个套接字和它自己的解析器线程对象,因此服务器可以处理来自客户端的数据流。解析器对象只是处理传入的数据并将其发送到数据库。

服务器/解析器生成器:

public void generateParsers() {
    while (keepRunning) {
        try {
            Socket socket = s.accept();
            // new connection
            t = new Thread(new Parser(socket));
            t.start();
        } catch (IOException e) {
            appLog.severe(e.getMessage());
        }
    }
}

解析器线程:

   @Override
    public void run() {
        while (!socket.isClosed() && socket.isConnected()) {
            try {
                BufferedReader bufReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String line = bufReader.readLine();
                String data = "";
                if (line == null) {
                    socket.close();
                } else if (Objects.equals(line, "<DATA")) {
                    while (!Objects.equals(line, "</DATA>")) {
                        data += line;
                        line = bufReader.readLine();
                    }
                    /*
                    Send the string that was build            
                    from the client's datastream to the database
                    using the parse() function.         
                    */
                    parse(data);
                    }
                }
            } catch (IOException e) {
                System.out.println("ERROR : " + e);
            }
        }
    }

我的设置可以正常工作,但问题是当连接的客户端过多时,它会给我的服务器带来太大的压力,因此有太多的线程同时解析数据。解析传入数据并将数据发送到数据库几乎不会影响性能。瓶颈主要是从连接的客户端并发读取客户端的数据流。

有什么方法可以优化我当前的设置吗?我正在考虑限制连接数量,一旦收到完整的数据文件,解析它并移动到连接队列中的下一个客户端或类似的东西。

【问题讨论】:

  • data += line; 你可以使用StringBuilder 重构这个字符串连接。您还可以分析您的代码以查找是否存在任何特定的瓶颈

标签: java multithreading sockets parsing


【解决方案1】:

瓶颈多是并发阅读

没有。瓶颈是字符串连接。使用StringBufferStringBuilder

当客户端断开连接时可能存在不当行为。很难相信这完全有效。它不应该:

  • 您应该在套接字的整个生命周期内使用相同的BufferedReader,否则您可能会丢失数据。
  • Socket.isClosed()Socket.isConnected() 不要做你认为他们做的事情:正确的循环终止条件是 readLine() 返回 null,或者抛出 IOException

    while ((line = bufReader.readLine()) != null)
    

如果客户端从不断开连接,则限制并发连接数可能无法实现。除了第一个 N 连接之外,您将完成的只是永远不会听客户,这不可能是您想要的。 “转移到下一个客户”永远不会发生。

【讨论】:

    【解决方案2】:

    如果您的问题确实是客户端连接时所做的任何事情都很昂贵,那么您将不得不使用客户端队列。最简单的方法是使用 ExecutorService 和 N 最大线程数。

    例如

    private ExecutorService pool=Executors.newFixedThreapPool(N);
    

    ... 然后

    Socket socket = s.accept();
    pool.submit(new Parser(socket)));
    

    这会将同时处理的客户端限制为 N,并将超过 N 的任何其他客户端排队。

    还取决于您对数据的处理方式,例如,您始终可以将流程拆分为多个阶段

    1. 从客户端读取原始数据并入队进行处理 - 关闭套接字等,这样您就可以节省资源
    2. 在单独的线程(可能是线程池)中处理数据并将结果排入队列
    3. 在另一个池中处理结果(检查有效性、持久化到数据库等)。

    如果您有一些阻塞操作,如网络 I/O 或昂贵的操作等,这将特别有用。

    在您的情况下,客户端不必等待整个后端进程完成。他只需要交付数据,因此将数据读取和解析/持久化为单独的阶段(子任务)听起来是合理的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-27
      • 2015-02-10
      • 1970-01-01
      • 2011-10-10
      • 1970-01-01
      相关资源
      最近更新 更多