我有以下逻辑(简化):

public class Application {

    public static volatile boolean stopServer;
    private static ScheduledExecutorService taskScheduler;

    private static Thread listenerThread;

    public static synchronized void switchStopServer() {
        stopServer = true;

        listenerThread.interrupt();
        taskScheduler.shutdownNow();
    }

    public static void main(String[] args) {
            int threadPoolSize = 4;
            taskScheduler = Executors.newScheduledThreadPool(threadPoolSize);

            listenerThread = new ListenerThread();
            taskScheduler.schedule(listenerThread, 0, TimeUnit.NANOSECONDS);
    }

}

public class ListenerThread extends Thread {

    private static ServerSocket serverSocket;
    private Socket socketConnection;

    @Override
    public void run() {
         while (!Application.stopServer) {
              try {
                   socketConnection = serverSocket.accept();
                   new CommunicatorThread(socketConnection).start();
              } catch (SocketException e) {
              } catch (Exception e) {
              }
         }
    }

    private static void closeServerSocket() {
         try {
              if (serverSocket != null && !serverSocket.isClosed()) serverSocket.close();
         } catch (Exception e) { }
    }

    @Override
    public void interrupt() {
         closeServerSocket();
         super.interrupt();
    }

}

我要实现的是以正确的方式终止Thread。首先,这(switchStopServer())是执行此操作的正确方法,还是有更好的解决方案?

我对 ScheduledExecutorService 有点困惑,因为shutdownNow()不会中断Thread ScheduledFuture.cancel(true) 也不会中断(至少对我而言不会),因此我无法中断ServerSocket.accept()。我知道,在我的示例中不需要ScheduledExecutorService,但在我的实际应用程序中是必需的。

最佳答案

我相信您的问题是,您混淆了ThreadRunnable。即使ListenerThread扩展了Thread,它实际上也不是它自己的线程。该线程由ExecutorService线程池管理,该线程池仅调用run()方法。这只是[sort]的工作,因为Thread也实现了Runnable。当您调用ListenerThread.interrupt()时,尽管您正在调用interrupt()方法,但并不直接在调用线程中中断线程池中的线程。这应该关闭套接字,因为它从外部调用closeServerSocket()

当您调用ScheduledFuture.cancel(true)shutdownNow()时,池线程应该被中断,但这不会在那里调用您的interrupt()方法。您可以通过在Thread.currentThread().isInterrupted()方法中使用run()来测试中断。

您应该从扩展ListenerThread更改Thread,而仅执行Runnable(请参见下方的编辑)。您将需要在run()方法中执行类似以下循环的操作:

while (!Application.stopServer && !Thread.currentThread().isInterrupted()) {

要中断accept()方法,您将不得不从另一个线程关闭serverSocket。这很可能由调用interrupt()的线程完成。它应该关闭套接字,在线程池中关闭shutdownNow()cancel(),然后它可以等待池终止。

编辑:

实际上,我想知道为什么您要为ListenerThread使用一个池,因为将只有其中一个池,它会立即进行调度,并且它只是直接在任何连接上启动一个新线程。我将完全删除您的taskScheduler池,保持ListenerThread扩展Thread,只调用new ListenerThread().start();

外线程仍将仅关闭serverSocket以停止ListenerThread。如果还需要关闭所有连接,则ListenerThread需要保留socketConnection的集合,以便当close()抛出n accept()时可以在它们上调用IOException

另外,当前您的private Socket socketConnection;具有误导性,因为在每次调用accept()之后,它都会改变。我将其重写为:
 Socket socketConnection = serverSocket.accept();
 new CommunicatorThread(socketConnection).start();

关于java - 终止应用程序和ScheduledExecutorService;线,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10733500/

10-10 19:51