2012-05-24 63 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