Short:在Java中,如何结束来自某个运行线程的无限循环(接受传入连接)?
Long:我使用这个示例作为代码的基础。
我有一个ExecutorService
,它管理线程池并接受主循环中的传入连接。主循环的停止条件是服务是否已通过isShutdown()
关闭。
我的例子是:当一个线程收到一个";再见";顺序,那么所有线程都必须尽可能优雅地停止,并且主无限循环必须退出。然而,到目前为止,我还没有设法停止在isShutdown()
条件下运行的循环。
有许多问答;一个关于用ExecutorService
杀死线程的热门话题,但我还没有找到任何解决带条件的无限循环问题的方法。我试过:
- 中断:我可以中断生成的线程,但无限循环条件仍将运行并将新线程排入队列
- 易失性变量:它们可以方便地协调正在运行的线程,但我遇到了与上面相同的问题
- 将
ExecutorService
作为paramether传递给线程:然后它只是从接收"的线程调用.shutdown()
、.shutdownNow()
、awaitTermination()
;再见";,但因为Java是如何将对象作为参数传递的,所以我没有改变全局状态来中断主循环,它仍然在运行
我不知道我是否过于坚持isShutdown()
条件,也不知道是否应该使用另一种方法来解决这个问题。
这是一个稍微修改的例子,以检查消息是否为"0";再见";。我正在使用telnet
作为客户端来测试它
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ExecutorHttpd {
ExecutorService executor = Executors.newFixedThreadPool(3);
public void start(int port) throws IOException {
final ServerSocket ss = new ServerSocket(port);
while (!executor.isShutdown())
executor.submit(new TinyHttpdConnection(ss.accept()));
ss.close();
}
public void shutdown() throws InterruptedException {
executor.shutdown();
executor.awaitTermination(30, TimeUnit.SECONDS);
executor.shutdownNow();
}
public static void main(String argv[]) throws Exception {
if(argv.length != 1) {
System.out.println("Wrong number of arguments");
System.out.println("tUsage: ExecutorHttpd PORT_NUMBER");
return;
}
int port = Integer.parseInt(argv[0]);
new ExecutorHttpd().start(port);
}
}
class TinyHttpdConnection implements Runnable {
Socket client;
TinyHttpdConnection(Socket client) throws SocketException {
this.client = client;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
OutputStream out = client.getOutputStream();
String request = in.readLine();
System.out.println("Request: " + request);
if(request.equals("bye")) {
System.out.println("End all threads");
}
byte[] data = "hello".getBytes();
out.write(data, 0, data.length);
out.flush();
client.close();
} catch (IOException e) {
System.out.println("I/O error " + e);
}
}
}
关闭执行器不会对当前运行的作业产生任何影响,它只会影响正在侦听此事件的任何内容,"被动"查询该事件,并影响执行器池如何处理其作业系统(例如,向其提供任何新作业都不会起作用,任何尚未启动的排队作业也永远不会起作用)。
关键阻断剂是serverSocket.accept()
。
你想阻止那个人逃跑。
javadoc非常清楚:在serversocket上调用close()
,瞧,accept
方法将停止等待(确切地说,通过抛出SocketException
)。
因此,当您想将其全部关闭时,请在serversocket上调用.close()
。确保处理随后发生的socketexception,这应该包括检查您得到的socketexception的类型。您希望在通过.accept()
主动等待新套接字时,由显式close()
调用ServerSocket
引起的套接字被忽略(正如您所知,它来自哪里,而且是故意的),但不希望任何其他SocketException。在不知道异常产生的确切原因的情况下,默默地忽略异常是一个非常糟糕的主意。