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のは、適切な方法で終了することです。まず第一に、これswitchStopServer()はそれを行う正しい方法ですか、それともより良い解決策がありますか?

sを中断しないScheduledExecutorServiceので、私は少し混乱しています。また、 (少なくとも私にとっては中断しません)、中断することはできません。私の例では、の必要はありませんが、実際のアプリケーションでは必要です。shutdownNow()ThreadScheduledFuture.cancel(true)ServerSocket.accept()ScheduledExecutorService

4

1 に答える 1

4

私が信じるあなたの問題は、あなたが混乱ThreadしていてRunnable. ListenerThreadextendsですがThread、実際には独自のスレッドではありません。ExecutorServiceスレッドは、メソッドを呼び出しているスレッドプールによって管理されますrun()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実際、プールは1 つしかなく、すぐにスケジュールされ、任意の接続で新しいスレッドを直接開始するだけなので、なぜプールを使用しているのか疑問に思います。taskSchedulerプールを完全に削除し、 をListenerThread拡張し続けThread、 を呼び出すだけnew ListenerThread().start();です。

外側のねじ山は依然として を閉じてserverSocketを停止しListenerThreadます。すべての接続も閉じる必要がある場合は、が をスローしたときにそれらを呼び出すことができるように、 は周りListenerThreadのコレクションを保持する必要があります。socketConnectionclose()accept()IOException

また、現在、private Socket socketConnection;which を呼び出すたびに変更されるため、誤解を招く可能性がありますaccept()。私はそれを次のように書き直します:

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