我有以下逻辑(简化):
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
,但在我的实际应用程序中是必需的。 最佳答案
我相信您的问题是,您混淆了Thread
和Runnable
。即使ListenerThread
扩展了Thread
,它实际上也不是它自己的线程。该线程由ExecutorService
线程池管理,该线程池仅调用run()
方法。这只是[sort]的工作,因为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
使用一个池,因为将只有其中一个池,它会立即进行调度,并且它只是直接在任何连接上启动一个新线程。我将完全删除您的taskScheduler
池,保持ListenerThread
扩展Thread
,只调用new ListenerThread().start();
。外线程仍将仅关闭
serverSocket
以停止ListenerThread
。如果还需要关闭所有连接,则ListenerThread
需要保留socketConnection
的集合,以便当close()
抛出n accept()
时可以在它们上调用IOException
。另外,当前您的
private Socket socketConnection;
具有误导性,因为在每次调用accept()
之后,它都会改变。我将其重写为: Socket socketConnection = serverSocket.accept();
new CommunicatorThread(socketConnection).start();
关于java - 终止应用程序和ScheduledExecutorService;线,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10733500/