终止应用程序和ScheduledExecutorService;线

时间:2012-05-24 08:05:55

标签: java multithreading scheduled-tasks

我有以下逻辑(简化):

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()不会打断ThreadScheduledFuture.cancel(true)也不会打扰(至少对我而言,它不会),所以我不能打断ServerSocket.accept()。我知道,在我的例子中,不需要ScheduledExecutorService,但在我的实际应用中有。{/ p>

1 个答案:

答案 0 :(得分:4)

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

当您致电ScheduledFuture.cancel(true)shutdownNow()时,线程应该被中断,但会调用您的{{1方法那里。您可以使用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();