优化使用inputstreamreader的

时间:2017-02-01 16:41:29

标签: java multithreading sockets parsing

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

服务器/解析器生成器:

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);
            }
        }
    }

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

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

2 个答案:

答案 0 :(得分:3)

  

瓶颈主要是并发阅读

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

当客户端断开连接时,可能是不正确的行为。很难相信这一点有用。它不应该:

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

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

如果客户端从不断开连接,那么限制并发连接数就不可能实现。你所要做的就是永远不会听第一个 N 之外的客户来连接,这可能不是你想要的。 “转移到下一个客户”永远不会发生。

答案 1 :(得分:2)

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

例如

private ExecutorService pool=Executors.newFixedThreapPool(N);

... 然后

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

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

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

  1. 从客户端读取原始数据并排队等待处理 - 关闭套接字等,以便节省资源
  2. 在单独的线程(可能是线程池)中处理数据并将结果排入队列
  3. 在另一个池中执行结果(检查有效性,保留在DB等中)。
  4. 如果你有一些阻塞操作,如网络I / O或昂贵的等操作,这将特别有用。

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