Reputation: 187
In my Spring application, I start a thread like this.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.stereotype.Component;
@Component
public class RunBackgroundServices implements ApplicationListener<ContextRefreshedEvent> {
private final BackgroundServices backgroundServices;
private ExecutorService executor;
@Autowired
public RunBackgroundServices(BackgroundServices backgroundServices) {
this.backgroundServices= backgroundServices;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
executor = Executors.newSingleThreadExecutor();
executor.submit(backgroundServices);
}
public void onApplicationEvent(ContextStoppedEvent event) {
backgroundServices.close();
executor.shutdownNow();
}
}
Here is the thread BackGroundServices.
public class BackgroundServices extends Thread {
@Autowired
HL7Listener hL7Listener;
@Autowired
HISListener hISListener;
@Autowired
PollHIS pollHIS;
@Autowired
PollPatientPortal pollPatientPortal;
private static final Logger logger = LoggerFactory.getLogger(BackgroundServices.class);
public void run() {
logger.debug("BackgroundServices :: run");
try {
hL7Listener.start();
} catch (InterruptedException e) {
logger.error(e.getStackTrace().toString());
}
try {
hISListener.start();
} catch (InterruptedException e) {
logger.error(e.getStackTrace().toString());
}
while (true) {
pollHIS.start();
pollPatientPortal.start();
}
}
public void close(){
hL7Listener.stop();
hISListener.stop();
}
}
But when I stop the server, the thread continues running in the background. I have no control over the executor, is there a way to stop the thread?
Upvotes: 3
Views: 9357
Reputation: 403581
Calling shutdown
or shutdownNow
on an ExecutorService
will not stop the threads that are currently executing a task. shutdownNow
will wait for all currently executing tasks to finish. Stopping threads forcibly is a very bad thing, and no well-behaved Java code will do that.
If you want to stop your thread, then you need to pass a signal of some kind to the thread, and your code then needs to read that signal. ExecutorService#shutdownNow
does half of this for you - it sends an interrupt signal to the currently executing threads. Your code has the beginnings of interrupt handling, but it's not properly implemented.
When you get an InterruptedException
, you can't just log it and move on - that exception is telling you that your thread has been interrupted, and it needs to finish what it's doing and exit (see Java theory and practice: Dealing with InterruptedException - a superb article well worth reading for novices and experts alike). Rather than logging an error when you get InterruptedException
, your code needs to exit the method (e.g. using return
).
In your while loop, you then need to check to see if the thread has been interrupted, and exit if it has. So your run method now becomes something like this:
public void run() {
logger.debug("BackgroundServices :: run");
try {
hL7Listener.start();
hISListener.start();
} catch (InterruptedException e) {
logger.error(e.getStackTrace().toString());
return;
}
while (true) {
if (Thread.currentThread.isInterrupted()) {
logger.debug("Thread interrupted, exiting");
return;
}
pollHIS.start();
pollPatientPortal.start();
}
}
One last thing - BackgroundServices
shouldn't extend Thread
, it should just implement Runnable
. The ExecutorService
is treating it as a Runnable
because Thread
happens to implement that interface, but ExecutorService
creates and manages its own threads. Extending Thread
yourself is just going to result in confusion.
Upvotes: 4