优化使用inputstreamreader的java多线程服务器
我目前正在做一个项目,在这个项目中,我必须托管一个服务器,它获取一个输入流,解析数据并将其发送到数据库。每个连接到我的服务器的客户端都会发送一个inputstream,一旦连接,它就不会停止。每个客户机都分配了一个套接字和它自己的解析器线程对象,因此服务器可以处理来自客户机的数据流。解析器对象只处理传入数据并将其发送到数据库 服务器/解析器生成器:优化使用inputstreamreader的java多线程服务器,java,multithreading,sockets,parsing,Java,Multithreading,Sockets,Parsing,我目前正在做一个项目,在这个项目中,我必须托管一个服务器,它获取一个输入流,解析数据并将其发送到数据库。每个连接到我的服务器的客户端都会发送一个inputstream,一旦连接,它就不会停止。每个客户机都分配了一个套接字和它自己的解析器线程对象,因此服务器可以处理来自客户机的数据流。解析器对象只处理传入数据并将其发送到数据库 服务器/解析器生成器: public void generateParsers() { while (keepRunning) { try {
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);
}
}
}
@覆盖
公开募捐{
而(!socket.isClosed()&&socket.isConnected()){
试一试{
BufferedReader bufReader=新的BufferedReader(新的InputStreamReader(socket.getInputStream());
String line=bufReader.readLine();
字符串数据=”;
如果(行==null){
socket.close();
}else if(Objects.equals(line),如果您的问题确实是在连接客户端时所做的任何事情都是昂贵的,那么您必须使用客户端队列。最简单的方法是使用具有N个最大线程数的ExecutorService
比如说
private ExecutorService pool=Executors.newFixedThreapPool(N);
。。。
然后
Socket socket = s.accept();
pool.submit(new Parser(socket)));
这将同时将concurent客户端处理限制为N,并将超过N的任何其他客户端排队
还取决于您对数据所做的操作,例如,您始终可以将流程拆分为多个阶段
private ExecutorService pool=Executors.newFixedThreapPool(N);
从客户端读取原始数据并排队处理-关闭套接字等,这样可以节省资源
在单独的线程(可能是线程池)中处理数据,并将结果排队
在另一个池中对结果执行一些操作(检查有效性、持久化到DB等)
如果您有一些阻塞操作,如网络I/O或昂贵的操作等,这尤其有用
在您的情况下,客户端不必等待整个后端过程完成。他只需要交付数据,因此将数据读取和解析/持久化分为不同的阶段(子任务)听起来很合理。如果您的问题确实是在连接客户端时所做的任何事情都很昂贵,那么您必须使用客户端队列。最简单的方法是使用最大线程数为N的ExecutorService
比如说
private ExecutorService pool=Executors.newFixedThreapPool(N);
。。。
然后
Socket socket = s.accept();
pool.submit(new Parser(socket)));
这将同时将concurent客户端处理限制为N,并将超过N的任何其他客户端排队
还取决于您对数据所做的操作,例如,您始终可以将流程拆分为多个阶段
private ExecutorService pool=Executors.newFixedThreapPool(N);
从客户端读取原始数据并排队处理-关闭套接字等,这样可以节省资源
在单独的线程(可能是线程池)中处理数据,并将结果排队
在另一个池中对结果执行一些操作(检查有效性、持久化到DB等)
如果您有一些阻塞操作,如网络I/O或昂贵的操作等,这尤其有用
在您的案例中,客户端不必等待整个后端过程完成。他只需要交付数据,所以将数据读取和解析/持久化分为不同的阶段(子任务)听起来是合理的方法
瓶颈主要是并发读取
否。瓶颈是字符串连接。请使用StringBuffer
或StringBuilder
当客户断开连接时,可能会出现不正确的行为。很难相信这会起作用。它不应该:
- 您应该在套接字的生命周期内使用相同的
BufferedReader
,否则可能会丢失数据
Socket.isClosed()
和Socket.isConnected()
不要做你认为他们会做的事:正确的循环终止条件是readLine()
返回null,或抛出IOException
:
while ((line = bufReader.readLine()) != null)
如果客户端从未断开连接,则限制并发连接的数量不可能实现任何效果。您所要完成的就是,在连接的前N个客户端之外,永远不会侦听客户端,这不可能是您想要的。“移动到下一个客户端”将永远不会发生
瓶颈主要是并发读取
不。瓶颈是字符串连接。请使用StringBuffer
或StringBuilder
当客户断开连接时,可能会出现不正确的行为。很难相信这会起作用。它不应该:
- 您应该在套接字的生命周期内使用相同的
BufferedReader
,否则可能会丢失数据
Socket.isClosed()
和Socket.isConnected()
不要做你认为他们会做的事:正确的循环终止条件是readLine()
返回null,或抛出IOException
:
while ((line = bufReader.readLine()) != null)
如果客户端从未断开连接,则限制并发连接的数量不可能实现任何效果。您所要完成的只是在连接的前N个客户端之后再也不侦听客户端,这可能不是您想要的。将永远不会发生“移到下一个客户端”。data+=line;
您可以重构此字符串连接使用StringBuilder
进行串接。您还可以分析代码以查找是否存在任何特定瓶颈data+=line;
您可以使用StringBuilder
重构此字符串串接。您还可以分析代码以查找是否存在任何特定瓶颈