我目前正在编写一个服务器,多个客户端将连接到该服务器。通信协议基本上是服务器向客户端发送任务,客户端在任务执行时响应。客户端保持与服务器的连接,并且永远不应断开连接。
目前,我正在启动一个新的线程来处理每个客户端。从本质上讲,我目前的解决方案是这样的:(来自Java Concurrency in practice)
public class ThreadPerTaskWebServer {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(80);
while (true) {
final Socket connection = socket.accept();
Runnable task = new Runnable() {
public void run() {
handleRequest(connection);
}
};
new Thread(task).start();
}
}
private static void handleRequest(Socket connection) {
// request-handling logic here
}
}但我更喜欢使用Executor,因为它们看起来更稳定,伸缩性更好。因此,为了让服务器能够向客户端发送消息,我需要与运行客户端的执行器分开跟踪客户端。因此,如果我将客户端放在CopyOnWriteArrayList客户端中的什么位置,然后在Server类中有类似这样的内容:
Socket clientSocket = serverSocket.accept();
// The runnable that takes care of a client
ClientHandler c = new ClientHandler(clientSocket, this);
// Start executing the ClientHandler
exec.execute(c);
// Add clients to CopyOnWriteArrayList
clients.add(c);这将允许我遍历CopyOnWriteArrayList,以便向所有客户端发送命令并删除断开连接的客户端。这是一个健壮的解决方案吗?如果由于某种原因,runnable会将异常传播给Executor,那么Executor会发生什么情况?
发布于 2012-04-06 03:25:26
这是一个健壮的解决方案吗?
我想可以。您需要确保在固定大小的池中分配正确数量的线程,或者使用动态池。
如果由于某种原因,runnable会向其传播异常,那么Executor会发生什么情况?
如果您的代码抛出RuntimeException,则执行代码的执行器池线程将停止,但如果服务尚未关闭,则池线程计数将减少,并创建另一个线程。因此,线程池将继续正常运行。
这将允许我遍历CopyOnWriteArrayList,以便向所有客户端发送命令,并删除断开连接的客户端
当然,除非保存对它们的引用,否则不需要删除断开连接的那些。否则,我无法对此要求发表评论。
发布于 2012-04-06 03:31:10
如果你选择每个连接线程的方法,并且你不想使用NIO api,我相信这是一个很好的解决方案。但请记住,如果您的池大小小于并发请求的数量,则在之前的请求结束之前,您的客户端都处于挂起状态。
关于如果你的任务中出现异常会发生什么:线程终止,但executor将创建其他线程。
https://stackoverflow.com/questions/10034670
复制相似问题