我有以下逻辑(简化):
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()
不会打断Thread
,ScheduledFuture.cancel(true)
也不会打扰(至少对我而言,它不会),所以我不能打断ServerSocket.accept()
。我知道,在我的例子中,不需要ScheduledExecutorService
,但在我的实际应用中有。{/ p>
答案 0 :(得分:4)
我相信您的问题是您感到困惑Thread
和Runnable
。即使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();