Java 关闭时可靠地关闭线程池中的客户端套接字
我有一个简单的基于ServerSocket的java程序,它接受客户端连接并将其放入线程池(ThreadPoolExecutor): 问题是,当我试图关闭程序时,客户机线程会一直保持,直到另一端的连接关闭(jvm在此之前不会退出) 我可以尝试在服务器即将关闭时维护所有客户端对象并关闭它们的所有套接字。但我不知道如何维护它们?尤其是完成后移除它们 我尝试了etc,但这只给了我另一个对象(未来任务),而不是我正在寻找的客户对象 更新:Java 关闭时可靠地关闭线程池中的客户端套接字,java,sockets,network-programming,threadpool,Java,Sockets,Network Programming,Threadpool,我有一个简单的基于ServerSocket的java程序,它接受客户端连接并将其放入线程池(ThreadPoolExecutor): 问题是,当我试图关闭程序时,客户机线程会一直保持,直到另一端的连接关闭(jvm在此之前不会退出) 我可以尝试在服务器即将关闭时维护所有客户端对象并关闭它们的所有套接字。但我不知道如何维护它们?尤其是完成后移除它们 我尝试了etc,但这只给了我另一个对象(未来任务),而不是我正在寻找的客户对象 更新: 问题不是向列表中添加套接字,而是在完成后将其删除,因为无法使用a
问题不是向列表中添加套接字,而是在完成后将其删除,因为无法使用afterExecute(afaik)。在将套接字提交到池之前,将所有套接字存储在
列表中。然后关闭线程可以在所有套接字上调用close()
,这将导致被阻止的线程在所有客户端套接字上抛出SocketException
s.调用关闭输入()。这将导致相关线程认为对等线程已断开连接,因此优雅地退出。一种方法是让客户端在完成后返回自身(将来)。只需要一个列表,然后使用afterExecute方法
像这样:
pool =new ThreadPoolExecutor(...) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
// The future returns the Client object!
client = (Client)((FutureTask)r).get();
// Remove it from list of known clients
clients.remove(client);
}
};
while() {
socket = serverSocket.accept();
Client client = new Client(socket)
// Submit to pool, using client as the future return value
pool.submit(client, client);
// Add to list of known clients
clients.add(client);
}
// When app is closing
private shutdown() {
for(Client client : clients){
client.shutdown();
}
}
如果你不想让线程停止关机,那么你可以让它们成为守护进程线程。谢谢,但在这种情况下,我希望有序地关闭客户端。然后你应该在执行器上调用shutdown,并在可运行的实现中处理InterruptedExeception。不,这不起作用,因为客户端在I/O(套接字)上阻塞。流不会中断。您有两个选择:使用守护进程线程或在套接字连接上超时。后者将允许您定期检查当前中断状态,并尝试有序关机(但它会将关机延迟到超时值)。将客户端添加到列表很容易,但删除却不容易,因为我不知道它们何时完成。好了,池没有办法知道这一点。@MartinWickman您的客户机类可以在启动时将其套接字添加到列表中,并在关闭套接字时将其从池中删除。@EJP是的,这可能是最好的方法。另一种方法见我的答案。
pool =new ThreadPoolExecutor(...) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
// The future returns the Client object!
client = (Client)((FutureTask)r).get();
// Remove it from list of known clients
clients.remove(client);
}
};
while() {
socket = serverSocket.accept();
Client client = new Client(socket)
// Submit to pool, using client as the future return value
pool.submit(client, client);
// Add to list of known clients
clients.add(client);
}
// When app is closing
private shutdown() {
for(Client client : clients){
client.shutdown();
}
}