无法停止ExecutorService

时间:2014-01-19 12:42:53

标签: java scheduled-tasks task executorservice watchservice

我尝试使用executorService.shutdown();结束ExecutorService,如果这不起作用,请使用executorService.shutdown();。问题是,无法停止executorService并且程序仍在运行。

这是我的类,它将启动WatchService来监视目录的变化:

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();
        }
    }
} 

我从oracle java api] 1获得了方法stopWatcher()。 我写了一个简单的类来测试FileWatcher类。

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;

    }

}

因此,当我启动测试应用程序以启动FileWatcher并在此之后2秒结束时,程序会告诉我:Pool did not terminate。 我可以更改什么,以正确终止它?

顺便说一下,ConfigManager和FileHandler是接口,在那里我得到了我必须进行更改的路径。

2 个答案:

答案 0 :(得分:2)

在不分析代码的情况下,它不会关闭,因为任何线程都没有完成/正在保存资源。简单的脏解决方案是使用javadoc中的ExecuterService.shutdownNow()强制停止:

  

尝试停止所有正在执行的任务,停止处理   等待任务,并返回正在等待的任务列表   执行。

所以试试这个并分析ExecuterService.shutdownNow()返回的Runnables列表,你会看到哪个线程正在挂起,然后逐步调试,看看导致挂起的原因。

答案 1 :(得分:0)

shutDown()只会告诉执行人不接受任何新任务&amp;取消所有尚未运行的任务。正在运行的任务可以完成。

你在

中无限循环
    while (!Thread.currentThread().isInterrupted()) {
        key = waitForEvents(watcher, key);
    }

因为InterruptedException没有设置中断标志。

如果你改变了

    try {
        key = watcher.take();
    } catch (InterruptedException e) {
        executorService.shutdown();
    } catch (ClosedWatchServiceException e) {
        executorService.shutdown();
    }

    try {
        key = watcher.take();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    } catch (ClosedWatchServiceException e) {
        Thread.currentThread().interrupt();
    }

并在while循环后添加executorService.shutdown();(或保持原样)你应该没有问题。