Reputation: 1759
I try to end a ExecutorService with executorService.shutdown();
and if that didn't worked, with executorService.shutdown();
. The Problem is, that the executorService can't be stopped and the program is still running.
Here is my class which shall start a WatchService to watch a directory for changes:
public class FileWatcher {
/**
* This Class starts a WatchService to get changes on a specific folder.
*/
Path dir;
private final ConfigManager configManager;
private final FileHandler fileHandler;
private ExecutorService executorService;
public FileWatcher(ConfigManager configManager, FileHandler fileHandler) {
this.configManager = configManager;
this.fileHandler = fileHandler;
}
public void start() {
dir = configManager.getConfig().getJdfPath();
//executorService = Executors.newFixedThreadPool(1);
executorService = Executors.newSingleThreadExecutor();
Runnable runWatcher;
runWatcher = new Runnable() {
@Override
public void run() {
try {
startWatcher();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
executorService.execute(runWatcher);
}
private void startWatcher() throws IOException, InterruptedException {
/**
* Create a new WatchService which detects created and modified files. To
* let it detect deleted files add ENTRY_DELETE to dir.register().
*/
WatchService watcher = FileSystems.getDefault().newWatchService();
WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_MODIFY);
while (!Thread.currentThread().isInterrupted()) {
key = waitForEvents(watcher, key);
}
}
private WatchKey waitForEvents(WatchService watcher, WatchKey key) {
/**
* The WatchService tells the FileHandler the Filename of the changed or
* new file in the given folder.
*/
try {
key = watcher.take();
} catch (InterruptedException e) {
executorService.shutdown();
} catch (ClosedWatchServiceException e) {
executorService.shutdown();
}
for (WatchEvent<?> event : key.pollEvents()) {
fileHandler.setPath((Path) event.context());
}
key.reset();
return key;
}
public void stop() {
stopWatcher();
}
private void stopWatcher() {
executorService.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
executorService.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!executorService.awaitTermination(10, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
executorService.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
}
I got the method stopWatcher()
from the oracle java api]1.
I wrote a simple class to test the FileWatcher class.
public class TestFileWatcher {
static Path path;
static ConfigManager configmanager;
public static void main(String[] args) {
path = Paths.get("D:/testfolder");
FileHandler filehandler = new FileHandler() {
@Override
public void setPath(Path path) {
System.out.println("file: " + path);
}
@Override
public Path getPath() {
// TODO Auto-generated method stub
return null;
}
};
final Config config;
config = new Config() {
@Override
public Path getJdfPath() {
// TODO Auto-generated method stub
return path;
}
};
configmanager = new ConfigManager() {
@Override
public void injectConfig(Config config) {
// TODO Auto-generated method stub
}
@Override
public Config getConfig() {
// TODO Auto-generated method stub
return config;
}
};
configmanager.injectConfig(config);
filehandler.setPath(path);
final FileWatcher filewatcher = new FileWatcher(configmanager, filehandler);
filewatcher.start();
Timer timer = new Timer();
boolean stopped;
TimerTask closeWatcherTask = new TimerTask(){
@Override
public void run() {
System.out.println("filewatcher stopped.");
filewatcher.stop();
}
};
long duration = 2000;
timer.schedule(closeWatcherTask, duration);
return;
}
}
So, when I start the Test Application to start the FileWatcher and end it 2 seconds after that, the program tells me: Pool did not terminate
.
What can I change, to terminate it correctly?
By the way, the ConfigManager and FileHandler are interfaces, where I get the Path which I have to whatch for changes.
Upvotes: 0
Views: 1846
Reputation: 35232
Without analyzing your code it does not shutdown because any of the threads have not finished/are holding resources. The easy dirty solution is to do a force stop with ExecuterService.shutdownNow()
which states in javadoc:
Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
So try this and analyze the List of Runnables returned by ExecuterService.shutdownNow()
you get back to see which thread is hanging and then do a step by step debug and see what is causing the hang.
Upvotes: 2
Reputation: 63955
shutDown()
will only tell the executor to not accept any new tasks & cancels all tasks that are not runnuing yet. Tasks that are running are allowed to finish.
You are looping indefinitely in
while (!Thread.currentThread().isInterrupted()) {
key = waitForEvents(watcher, key);
}
because an InterruptedException
is not setting the interrupted flag.
If you change
try {
key = watcher.take();
} catch (InterruptedException e) {
executorService.shutdown();
} catch (ClosedWatchServiceException e) {
executorService.shutdown();
}
To
try {
key = watcher.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ClosedWatchServiceException e) {
Thread.currentThread().interrupt();
}
and add executorService.shutdown();
after the while loop (or keep it where it is) you should have no problem.
Upvotes: 0