从 运行 个线程之一结束无限循环(接受传入连接)

end an infinite loop (accepting incoming connections) from one of the running threads

Short:在 Java 中,如何结束 运行 线程之一的无限循环(接受传入连接)?

Long:我正在使用 this 示例作为我的代码的基础。

我有一个 ExecutorService 管理线程池并在主循环中接受传入连接。主循环的停止条件是服务是否已经关闭 isShutdown().

我的情况:当一个线程收到“再见”序列时,所有线程都必须尽可能优雅地停止,并且主无限循环必须退出。但是,到目前为止,我还没有设法停止在 isShutdown() 条件下运行的循环。

有很多关于用 ExecutorService 杀死线程的热问答,但我还没有找到任何解决条件无限循环问题的方法。我试过:

我不知道我是否过于拘泥于 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。在不知道异常原因的情况下默默地忽略异常是一个非常糟糕的主意。