1

我有以下逻辑(简化):

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的是以正确的方式终止 s 。首先,这 ( switchStopServer()) 是正确的方法,还是有更好的解决方案?

我对 s 有点困惑ScheduledExecutorService,因为shutdownNow()不会打断Threads,也不会ScheduledFuture.cancel(true)(至少对我来说没有),所以我不能打断ServerSocket.accept()。我知道,在我的示例中不需要ScheduledExecutorService,但在我的实际应用程序中需要。

4

1 回答 1

4

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

当您调用ScheduledFuture.cancel(true)orshutdownNow()时,线程应该被中断,但这不会在那里调用您的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()accept()抛出IOException.

此外,目前你有private Socket socketConnection;这具有误导性,因为它会在每次调用accept(). 我将其重写为:

 Socket socketConnection = serverSocket.accept();
 new CommunicatorThread(socketConnection).start();
于 2012-05-24T08:08:56.277 回答