从 运行 个线程之一结束无限循环(接受传入连接)
end an infinite loop (accepting incoming connections) from one of the running threads
Short:在 Java 中,如何结束 运行 线程之一的无限循环(接受传入连接)?
Long:我正在使用 this 示例作为我的代码的基础。
我有一个 ExecutorService
管理线程池并在主循环中接受传入连接。主循环的停止条件是服务是否已经关闭 isShutdown()
.
我的情况:当一个线程收到“再见”序列时,所有线程都必须尽可能优雅地停止,并且主无限循环必须退出。但是,到目前为止,我还没有设法停止在 isShutdown()
条件下运行的循环。
有很多关于用 ExecutorService
杀死线程的热问答,但我还没有找到任何解决条件无限循环问题的方法。我试过:
- 中断:我可以中断生成的线程,但无限循环条件仍然是 运行 并排队新线程。
- 易失性变量:它们可以方便地协调 运行 线程,但我遇到了与上述相同的问题。
- 将
ExecutorService
作为参数传递给线程:然后它只是从接收“再见”的线程调用 .shutdown()
、.shutdownNow()
、awaitTermination()
,但是因为 Java 如何将对象作为参数传递,所以我没有更改全局状态来打破主循环,它仍然是 运行。
我不知道我是否过于拘泥于 isShutdown()
条件以及我是否应该使用其他方法来解决这个问题。
此示例稍作修改以检查消息是否为“再见”。我正在使用 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);
}
}
}
关闭执行器不会对当前 运行 作业做任何事情,它只会影响正在侦听此事件的任何东西,'passively' 查询它,它会影响该执行器的方式pool 正在处理它的工作系统(例如,向它提供任何新工作都不会工作,并且任何尚未启动的排队工作永远不会工作)。
这里的关键障碍是 serverSocket.accept()
。
您想从 运行 停止那个。
javadoc 非常清楚:在 serversocket 上调用 close()
瞧,accept
方法将停止等待(通过抛出一个 SocketException
,准确地说).
所以,当你想关闭它时,在 serversocket 上调用 .close()
。确保处理随之而来的 socketexception,这应该涉及检查你得到的 SocketException 的 kind。您希望通过 close()
ing ServerSocket
而主动等待通过 .accept()
的新套接字被忽略(因为您知道它来自哪里,这是故意的) ),但不是任何其他 SocketExceptions。在不知道异常原因的情况下默默地忽略异常是一个非常糟糕的主意。
Short:在 Java 中,如何结束 运行 线程之一的无限循环(接受传入连接)?
Long:我正在使用 this 示例作为我的代码的基础。
我有一个 ExecutorService
管理线程池并在主循环中接受传入连接。主循环的停止条件是服务是否已经关闭 isShutdown()
.
我的情况:当一个线程收到“再见”序列时,所有线程都必须尽可能优雅地停止,并且主无限循环必须退出。但是,到目前为止,我还没有设法停止在 isShutdown()
条件下运行的循环。
有很多关于用 ExecutorService
杀死线程的热问答,但我还没有找到任何解决条件无限循环问题的方法。我试过:
- 中断:我可以中断生成的线程,但无限循环条件仍然是 运行 并排队新线程。
- 易失性变量:它们可以方便地协调 运行 线程,但我遇到了与上述相同的问题。
- 将
ExecutorService
作为参数传递给线程:然后它只是从接收“再见”的线程调用.shutdown()
、.shutdownNow()
、awaitTermination()
,但是因为 Java 如何将对象作为参数传递,所以我没有更改全局状态来打破主循环,它仍然是 运行。
我不知道我是否过于拘泥于 isShutdown()
条件以及我是否应该使用其他方法来解决这个问题。
此示例稍作修改以检查消息是否为“再见”。我正在使用 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);
}
}
}
关闭执行器不会对当前 运行 作业做任何事情,它只会影响正在侦听此事件的任何东西,'passively' 查询它,它会影响该执行器的方式pool 正在处理它的工作系统(例如,向它提供任何新工作都不会工作,并且任何尚未启动的排队工作永远不会工作)。
这里的关键障碍是 serverSocket.accept()
。
您想从 运行 停止那个。
javadoc 非常清楚:在 serversocket 上调用 close()
瞧,accept
方法将停止等待(通过抛出一个 SocketException
,准确地说).
所以,当你想关闭它时,在 serversocket 上调用 .close()
。确保处理随之而来的 socketexception,这应该涉及检查你得到的 SocketException 的 kind。您希望通过 close()
ing ServerSocket
而主动等待通过 .accept()
的新套接字被忽略(因为您知道它来自哪里,这是故意的) ),但不是任何其他 SocketExceptions。在不知道异常原因的情况下默默地忽略异常是一个非常糟糕的主意。