我正在编写一个客户端/套接字连接,并使用ThreadPools处理多个客户端。
在我的服务器启动后,我使用了几个资源。如果f.ex:服务器对客户端说它应该关闭,我想关闭所有的。
我仍然编码了一个基本的关闭功能:
public static void killClient() {
try {
threadpool.shutdown();
in.close();//client input
out.close();//client output
socket.close();
} catch(Exception e) {
System.out.println("Client has been shutdown! " + e);
e.printStackTrace();
}
}
我的问题是:
如何确保一切都已正常关闭,不再有任何东西运行?
如何确保一切都已正确关闭,并且不再运行?
我已经回答了下面的具体问题。
我认为"关闭"你的课程比集中精力关闭资源更重要。如果一个类(比如上面的Client
类)封装了线程池和套接字等资源,那么它应该有一个close()
方法(比如上面killClient()
)。如果服务器分叉客户端,那么它应该管理它们,以便server.close()
调用各种client.killClient()
方法。
如果您对正确关闭各种类、在任何地方使用try {} finally {}
块持谨慎态度,则不必担心未关闭的资源和挂起的线程。
这很难做到,并且没有针对所有资源类型的一揽子答案。这里有几个想法可能会有所帮助。
-
对于线程,您可以使用类似
Threads.getAllStackTraces()
的东西来显示剩余的线程。如果你在程序启动和结束时比较这个列表,你应该能够看到剩下的内容。 -
文件描述符要难得多。如果您在Linux上运行,那么您可以查看
/proc/self/fd
目录,看看哪些描述符仍然打开。再次比较开始和结束。您还可以查看应用程序中的OpenFileDescriptorCount
JMX变量(java.lang:type=OperatingSystem
),但它只提供了没有上下文的描述符数量。 -
没有简单的方法可以检测其他资源中的泄漏。您可以将
ResourceManager
类型的类封装在它们周围,从中"生成"one_answers"释放"资源,但这需要编程支持。如果您在管理器之外创建资源,则没有简单的方法来检测泄漏。 -
这种机制的一个例子是我为ORMLite测试所做的工作。ORMLite打开和关闭了很多数据库连接,我想确保我的代码中没有泄漏它们。我为数据库连接创建了一个包装器,在创建数据库连接时,它会向管理器注册自己,在关闭数据库连接时取消注册自己。然后我可以确保
assertTrue(connectionManager.isAllConnectionsClosed());
。不确定这是否有帮助。
如果您使用Java7,那么您可以将try-with-resources
构造用于所有可关闭的对象,如Socket、Connection、Statement等,一旦它们超出范围,就会自动关闭它们。
如果in.close()使out.close()失败,并且永远不会调用socket.colose(。
还要确保从finally块中调用方法killclient()。