简体   繁体   English

Java:正确关闭多个线程

[英]Java: Closing multiple threads properly

I'm making a simple server that will spawn multiple threads to handle multiple clients. 我正在制作一个简单的服务器,它将生成多个线程来处理多个客户端。 I was wondering the proper way to shut down and close all the various streams and threads when the server is terminated. 我想知道在终止服务器时关闭和关闭所有各种流和线程的正确方法。

I added a shutdownHook that runs a method that tells the server to shutdown. 我添加了一个shutdownHook,它运行告诉服务器关闭的方法。 The server, in turn, broadcasts the shutdown call to all of the threads it has opened, which sets a "isClosed" boolean in each thread to true. 反过来,服务器将关闭调用广播到它已打开的所有线程,这会将每个线程中的“ isClosed”布尔值设置为true。

What I'm expecting is that each thread, when reaching the end of the run() method and looping up again, hits the while(!isClosed) conditional, thereby properly terminating themselves by closing all the proper sockets/streams and returning. 我期望的是,每个线程在到达run()方法的末尾并再次循环运行时,都会达到while(!isClosed)条件,从而通过关闭所有适当的套接字/流并返回来正确地终止自身。

However, I don't know if this will properly close everything since the program should terminate after the shutdownhook completes. 但是,我不知道这是否可以正确关闭所有内容,因为该程序应在关闭挂机完成后终止。 It completes fairly early since all it does is propagate the closing message. 由于它所做的只是传播关闭消息,因此它相当早完成。 Does this mean that some threads won't get enough time to properly close? 这是否意味着某些线程将没有足够的时间正确关闭?

If so, would the best method be to have the shutdownhook manually close every thread, ensuring that they have closed, before returning? 如果是这样,最好的方法是让shutdownhook在返回之前手动关闭每个线程,确保它们已关闭吗?

Using an ExecutorService is the modern way of doing it. 使用ExecutorService是现代的方法。 It takes so much of the fiddly bits away from the code. 它占用了代码中那么多巧妙的位。

Here is a good place to start. 是一个不错的起点。

You are correct that the threads will likely not have enough time to terminate properly if the server is terminated. 您是正确的,如果服务器终止,线程可能没有足够的时间正确终止。 However, depending on what you're trying to do, this may or may not be a problem. 但是,根据您要尝试执行的操作,这可能会或可能不会出现问题。 If there is no cleanup work needed, then you probably do not need to worry about it because having the threads abruptly terminate will cause no issues. 如果不需要清理工作,那么您可能不必担心,因为线程突然终止不会造成任何问题。

However, if there is cleanup work that needs to be done (such as writing to a database), then you need something else. 但是,如果需要完成清理工作(例如写入数据库),那么您还需要其他工作。 The best way to do this (in Java) is using an Executor/ExecutorService and related items ( http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html ). 最好的方法(使用Java)是使用Executor / ExecutorService和相关项目( http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html )。 Your problem is addressed well by these, plus you get some nice freebies such as thread pool management so that scaling is much easier. 这些可以很好地解决您的问题,此外,您还可以获得一些不错的免费赠品,例如线程池管理,因此扩展变得更加容易。 If you spawn a new thread for every client you will have big problems when you try to scale later because you can't be creating a million threads per minute, for example. 如果为每个客户生成一个新线程,则稍后尝试扩展时会遇到很大的问题,因为例如每分钟不能创建一百万个线程。

Using the Excecutor stuff is a bit of an adjustment if you're used to using raw threads, but it is worth the research. 如果您习惯使用原始线程,那么使用Excecutor的东西会有些调整,但这值得研究。 Good luck! 祝好运!

The shutdownHook happens too late in the the cycle to be useful that way. shutdownHook在周期中发生得太晚,以至于无法以这种方式使用。 It is expected to complete quickly and the JVM is already on the way down, which could take existing threads with it if they are daemons. 预计它将很快完成,并且JVM已经处于关闭状态,如果它们是守护程序,则可能会将现有线程与它一起使用。

I would just set a read timeout on the connection threads of say 15-30 seconds. 我只是将连接超时设置为15-30秒。 If the timeout happens (SocketTimeoutException) , close the socket and exit the thread. 如果发生超时(SocketTimeoutException) ,请关闭套接字并退出线程。 The clients will have to cope with dropped connections of course, but they have to do that already. 客户当然必须处理掉线的连接,但是他们必须已经这样做。 Then when you want to shutdown, just stop accepting new connections (eg close the ServerSocket and have its accept thread cope correctly with the resulting exception). 然后,当您要关闭时,只需停止接受新的连接即可(例如,关闭ServerSocket并使其接受线程正确处理产生的异常)。 When all the existing connection threads have exited, the JVM will exit, and that should really take no longer than the timeout period plus the length of the longest transaction. 当所有现有连接线程均已退出时,JVM将退出,这实际上应该不超过超时时间加上最长事务的时间。 Make sure the connection threads aren't daemons. 确保连接线程不是守护程序。

If you don't mind clients getting chopped off in mid-transaction, just call System.exit(). 如果您不介意客户在交易中被砍掉,只需调用System.exit().

Have you considered making your threads daemon threads. 您是否考虑过将线程守护进程线程化。 just add t.setdaemon(true); 只需添加t.setdaemon(true); before calling the start method of the thread. 在调用线程的start方法之前。 If these threads should be ended when the program is ended than making them daemon will kill them once all the other non daemon thread has ended. 如果这些线程应在程序结束时结束,则使它们成为守护程序将在所有其他非守护程序线程结束后将其杀死。 threads that are used in threadpool are good example for threads that should be daemons. 线程池中使用的线程是应该作为守护程序的线程的一个很好的例子。 and i really think it can be useful for you. 我真的认为这对您可能有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM