在应用程序退出时停止观察者服务

stop watcher service on application quit

我使用 gradleapplication 插件到 运行 监视目录变化的应用程序。

我的主要 class 看起来像这样

public static void main(String[] args) throws IOException {
    WatcherThread thread = new WatcherThread(EXTENSION_FOLDER);
    thread.start();

    try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
        String input = null;
        ConsoleInputController controller = new ConsoleInputController(br);
        while (!QUIT_COMMAND.equals(StringUtils.trim(input))) {
            System.out.println(CONSOLE_TEMPLATE);
            System.out.println("input (to exit write [quit]):> ");

            input = br.readLine();
            controller.handleInput(input);
        }
    } catch (IOException exc) {
        LOGGER.error("Failed to process input.", exc);
    }

    thread.stopThread();
}

WatcherThread 是一个使用 WatcherService 的线程 class(java 的 WatchService 上的一些包装器)

public class WatcherThread extends Thread {
    private static final Logger LOGGER = LoggerFactory.getLogger(WatcherThread.class);

    private boolean watch = true;
    private WatcherService watcherService;

    public WatcherThread(String searchingPath) throws IOException {
        watcherService = new WatcherService(Paths.get(searchingPath));
    }

    @Override
    public void run() {
        LOGGER.info("Artifact watching thread started.");
        while(watch) {
            if (!watcherService.watch()) {
                break;
            }
        }
        LOGGER.info("Artifact watching thread stopped.");
    }

    public void stopThread() {
        watch = false;
    }
}

WatcherService 看起来像这样

public class WatcherService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WatcherThread.class);

    private final WatchService watcher;
    private final Map<WatchKey, Path> keys;
    private boolean trace;

    WatcherService(Path dir) throws IOException {
        watcher = FileSystems.getDefault().newWatchService();
        keys = new HashMap<>();

        register(dir);

        trace = true;
    }

    private void register(Path dir) throws IOException {
        WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
        if (trace) {
            Path prev = keys.get(key);
            if (null == prev) {
                LOGGER.info("Register path: [{}].", dir);
            } else {
                if (!dir.equals(prev)) {
                    LOGGER.info("Updated path: [{}] -> [{}].", prev, dir);
                }
            }
        }
        keys.put(key, dir);
    }

    boolean watch() {
        WatchKey key;
        try {
            key = watcher.take();
        } catch (InterruptedException exc) {
            return false;
        }

        Path dir = keys.get(key);
        if (null == dir) {
            LOGGER.warn("WatchKey is not recognized!");
            return false;
        }

        // forEach?
        for (WatchEvent event: key.pollEvents()) {
            LOGGER.info("Polling events");
            WatchEvent.Kind kind = event.kind();
            if (OVERFLOW == kind) {
                continue;
            }

            WatchEvent<Path> ev = (WatchEvent<Path>) event;
            Path name = ev.context();
            Path child = dir.resolve(name);

            LOGGER.info("Event occurred [{}] in [{}].", event.kind().name(), child);
            WatchEventResolver.resolveEvent(ev, child);
        }

        boolean valid = key.reset();
        if (!valid) {
            keys.remove(key);

            if (keys.isEmpty()) {
                return false;
            }
        }

        return true;
    }
}

当我不 start 我的 WatcherThread - 控制台输入工作正常。例如,我可以毫无问题地 quit。但是当我 运行 线程并想退出时,它会等待几秒钟然后才结束。

据我了解,WatchService无法停止观看目录。

如何在 quit 应用程序上立即停止它?

您的 WatcherService class 中似乎需要一个额外的方法来调用 watcher.close()。然后,在您的 WatcherThread class 中,您可以在 stopThread() 中调用该方法。

Javadoc for WatchService 中,您可以看到 take() 一直在等待。您可以通过关闭它来强制它完成。