I have the following logic (simplified):
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();
}
}
What I want to achieve, is to terminate Threads the proper way. First of all, is this (switchStopServer()) the correct way to do that, or are there any better solutions?
I’m a little confused with the ScheduledExecutorService, because shutdownNow() does not interrupt the Threads, neither does ScheduledFuture.cancel(true) (at least for me it doesn’t), so I can’t interrupt ServerSocket.accept(). I know, in my example there is no need for the ScheduledExecutorService, but in my real application there is.
Your problem I believe is that you are confusing
ThreadandRunnable. Even thoughListenerThreadextendsThread, it is actually not it’s own thread. The thread is managed by theExecutorServicethread-pool which is just calling yourrun()method. This is only [sort of] working becauseThreadalso implementsRunnable. When you callListenerThread.interrupt()you are not interrupting the thread in the thread-pool although you are calling yourinterrupt()method but just directly in the calling thread. This should close the socket since it callscloseServerSocket()from the outside.When you call
ScheduledFuture.cancel(true)orshutdownNow(), the pool thread(s) should be interrupted but this will not call yourinterrupt()method there. You can test for the interruption by usingThread.currentThread().isInterrupted()in yourrun()method.You should change
ListenerThreadfrom extendingThreadand instead have it just implementRunnable(see edit below). You will want to do something like the following loop in yourrun()method:To interrupt the
accept()method, you are going to have to close theserverSocketfrom another thread. Most likely this will be done by the thread that is callinginterrupt(). It should close the socket,shutdownNow()orcancel()the thread-pool, and then it can wait for the pool to terminate.Edit:
Actually, I wonder why you are using a pool for your
ListenerThreadsince there will only ever be one of them, it is being scheduled immediately, and it is just starting a new thread on any connection directly. I would remove yourtaskSchedulerpool entirely, keepListenerThreadextendingThread, and just callnew ListenerThread().start();.The outer thread would still just close the
serverSocketto stop theListenerThread. If you also need to close all of the connections as well then theListenerThreadneeds to keep a collection of thesocketConnectionaround so it can callclose()on them when theaccept()throws a nIOException.Also, currently you have
private Socket socketConnection;which is misleading because it will change after every call toaccept(). I’d rewrite it as: