1

我目前正在编写一个多个客户端将连接到的服务器。通信协议基本上是服务器向客户端发送任务,客户端在执行任务时响应。客户端保持与服务器的连接,并且永远不应断开连接。

目前我正在启动一个新线程来处理每个客户端。在精神上,我目前的解决方案是这样的:(来自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
    }
}

但我想使用 Executors,因为它们看起来更稳定且可扩展性更好。因此,为了让服务器能够向客户端发送消息,我需要将客户端与运行它们的 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 以便向所有客户端发送命令并删除断开连接的客户端。这是一个强大的解决方案吗?如果一个可运行对象由于某种原因会传播一个异常给它,那么 Executor 会发生什么?

4

2 回答 2

1

如果您选择每个连接方法的线程并且您不想使用 NIO api,我相信这是一个很好的解决方案。但请记住,如果您的池大小小于并发请求的数量,那么您的客户端将处于待处理状态,直到之前的请求结束。

关于如果您的任务出现异常会发生什么:线程终止但执行程序将创建其他线程。

于 2012-04-05T19:31:09.953 回答
1

这是一个强大的解决方案吗?

是的,我想是这样。您需要确保在固定大小的池中分配正确数量的线程或使用动态池。

如果一个可运行对象由于某种原因会传播一个异常给它,那么 Executor 会发生什么?

如果您的代码抛出 a RuntimeException,则执行代码的执行器池线程将停止,但池线程计数将减少,如果服务尚未关闭,则会创建另一个线程。所以线程池会继续正常运行。

这将允许我遍历 CopyOnWriteArrayList 以便向所有客户端发送命令并删除断开连接的客户端

当然,除非您保存对它们的引用,否则您不需要删除断开连接的那些。否则我不能真正评论这个要求。

于 2012-04-05T19:25:25.580 回答