2012-05-24 64 views
1

我有以下逻辑(简体):终止应用程序和ScheduledExecutorService;螺纹

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())这样做的正确方法,还是有更好的解决方案?

我与ScheduledExecutorService有点困惑,因为shutdownNow()不中断Thread S,同样没有ScheduledFuture.cancel(true)(至少对我来说它并没有),所以我不能中断ServerSocket.accept()。我知道,在我的例子中,不需要ScheduledExecutorService,但是在我的真实应用程序中有。

+0

你为什么要按照预定的方式在ServerSocket上监听?任何具体原因?如果你有一个单独的专用线程在一个紧密的循环中监听一个ServerSocket并处理新的连接到新产生的线程或执行程序服务,设计可能会更简单。 – Zaki

+1

@Zaki我想,因为我以预定的方式启动其他线程,所以我将只使用同一个池来启动所有线程,所以当需要终止时,我只需调用'shutdownNow()'。但是你是对的,我不应该安排他们。谢谢! –

回答

4

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

当你调用ScheduledFuture.cancel(true)shutdownNow(),将线程(S)应中断,但这将不会调用interrupt()方法那里。您可以在run()方法中使用Thread.currentThread().isInterrupted()来测试中断。

您应该延长Thread改变ListenerThread,而是有它只是实现Runnable见下文编辑)。您将要执行类似下面的循环在你run()方法:

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

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

编辑:

其实,我不知道为什么你使用的是池您ListenerThread自会有永远只能是其中之一,它被立即安排,它只是在开始一个新的线程任何连接直接。我会完全删除您的taskScheduler游泳池,请继续ListenerThread延伸Thread,然后致电new ListenerThread().start();

外螺纹仍然会关闭serverSocket停止ListenerThread。如果您还需要关闭所有连接,那么ListenerThread需要保留socketConnection的一个集合,以便在accept()引发时可以拨打close()

此外,您目前有private Socket socketConnection;这是误导性的,因为它会在每次致电accept()后发生变化。我会将它改写为:

Socket socketConnection = serverSocket.accept(); 
new CommunicatorThread(socketConnection).start(); 
+0

还是有点困惑。在调试中,实际调用中断方法,并且应用程序成功终止。如果我更改为'Runnable',应该如何中断'accept()'命令? –

+0

对不起@Daniel。 'interrupt()'被调用,但直接在调用线程中调用 - 而不是从线程池中的线程调用。这意味着你将会遇到同步问题。 – Gray

+0

@Daniel您将需要关闭线程外部的'serverSocket' - 很可能来自尝试执行中断的同一线程。 – Gray