我有点惊讶,watch服务应该被实现为一个带有轮询循环的进程/线程。我不记得java中还有其他api应该这么做。将它实现为一组回调(侦听器、观察者等)不是更好吗?顺便说一句,有没有第三方库可以做到几乎相同,但使用回调模型?
3pmvbmvn1#
apachecommons有一些文件监视服务,我认为这些服务比java7中的要好得多。我不确定他们是否使用回调,但在我看来,它们更直观。是的,我认为观察者模型会更好。我在某个地方读到,用java实现这一点有点困难,因为它运行在一个虚拟机上,要获得文件的侦听器,需要直接与os对话。我不确定的细节或有效性这虽然。
ut6juiuv2#
您不必使用轮询,您可以使用watchservice.take(),它在发生更改时立即返回。是的,它需要一个线程,但是单个线程可以用于监视多个对象。因此,很容易实现一个拥有监视线程并允许为每个对象注册回调的singleton。至于第三方库,请看guava eventbus。我没有试过,也不确定是否适合你的需要。
tvz2xvvm3#
我以亚历克赛的回答为基础,但我认为他还不够清楚。。。请看下面的示例代码:
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; 也是至关重要的;这是我在写关于亚历克赛答案的评论时忘记的。我的假设是 take() 由调用 register() ,因此在我的用户代码中不应返回任何键,因为register()已经使用了它。由于这个错误的假设,我没有意识到到底发生了什么。
println(key)
println(k)
take()
WatchService
if(!k.reset()) break;
register()
3条答案
按热度按时间3pmvbmvn1#
apachecommons有一些文件监视服务,我认为这些服务比java7中的要好得多。我不确定他们是否使用回调,但在我看来,它们更直观。
是的,我认为观察者模型会更好。我在某个地方读到,用java实现这一点有点困难,因为它运行在一个虚拟机上,要获得文件的侦听器,需要直接与os对话。我不确定的细节或有效性这虽然。
ut6juiuv2#
您不必使用轮询,您可以使用watchservice.take(),它在发生更改时立即返回。是的,它需要一个线程,但是单个线程可以用于监视多个对象。因此,很容易实现一个拥有监视线程并允许为每个对象注册回调的singleton。
至于第三方库,请看guava eventbus。我没有试过,也不确定是否适合你的需要。
tvz2xvvm3#
我以亚历克赛的回答为基础,但我认为他还不够清楚。。。请看下面的示例代码:
如果你检查一下
println(key)
/println(k)
输出时,您将看到同一个对象被反复返回;take()
每次发出该键的信号时返回,以便使用多个具有相同属性的键WatchService
,只需检查每次返回的密钥。这也意味着你的循环块,只要关键是没有信号-正是你想要的。这个
if(!k.reset()) break;
也是至关重要的;这是我在写关于亚历克赛答案的评论时忘记的。我的假设是take()
由调用register()
,因此在我的用户代码中不应返回任何键,因为register()已经使用了它。由于这个错误的假设,我没有意识到到底发生了什么。