7

Watch Service 应该被实现为带有轮询循环的进程/线程,这让我有点惊讶。我不记得应该使用 Java 中的任何其他 API。

将其实现为一组回调(侦听器、观察者等)不是更好吗?

顺便说一句 - 是否有任何第三方库几乎相同,但使用回调模型?

4

3 回答 3

4

Apache Commons有一些文件监视服务,我认为它们比 Java 7 中的要好得多。我不确定它们是否使用回调,但在我看来它们更直观。

是的,我认为观察者模型会好得多。我在某处读到,使用 Java 执行此操作有点困难,因为它通过虚拟机运行,并且要让您需要直接与操作系统对话的文件的侦听器。我不确定这个的细节或有效性。

于 2013-06-05T22:10:21.700 回答
4

我以 Alexeis 的回答为基础,但我认为他不够清楚......看看这个示例代码:

WatchService service = dir.getFileSystem().newWatchService();
WatchKey key = dir.register(service, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
System.out.println(key);

for(;;) {
    WatchKey k = service.take();
    System.out.println(k);
    for(WatchEvent<?> ev:k.pollEvents()) {
        System.out.println(ev.kind());
        if(ev.kind() == OVERFLOW) continue;
        //TODO
        System.out.println(ev.context());
    }
    if(!k.reset()) break;
}

key.cancel();

如果您检查println(key)/println(k)输出,您会看到一遍又一遍地返回相同的对象;take()每次发出该键的信号时都会返回,因此要使用相同的多个键WatchService,只需检查每次返回的键。这也意味着只要没有发出密钥信号,您的循环就会阻塞 - 这正是您想要的。

if(!k.reset()) break;也很关键;这是我在写我对 Alexeis 答案的评论时忘记的。我的假设是take()由 调用register(),因此在我的用户代码中不应返回任何键,因为 register() 已经使用了它。由于这种错误假设,我不知道实际发生了什么。

于 2013-07-16T18:27:53.563 回答
3

您不必使用轮询,您可以使用 WatchService.take(),它会在发生更改时立即返回。是的,它需要一个线程,但是单个线程可以用于被监视的多个对象。所以很容易实现一个拥有观察线程并允许为每个对象注册回调的单例。

至于第三方库,请查看Guava EventBus。我没有尝试过,不确定它是否符合您的需求。

于 2013-06-06T10:27:56.017 回答