2013-06-05 8 views
5

Byłem nieco zaskoczony, że usługa Watch powinna być wdrożona jako proces/wątek z pętlą odpytywania. Nie pamiętam żadnego innego API w Javie, które powinno to robić.Usługa Watch Java 7 pętla odpytywania

Czy nie byłoby lepiej zastosować go jako zestaw wywołań zwrotnych (słuchacze, obserwatorzy itp.)?

BTW - czy istnieje jakaś niezależna biblioteka, która robi to samo, ale używa modelu callback?

+1

Nie rozumiem tutaj problemu. Nawet w przypadku modelu oddzwaniania musisz uzyskać zdarzenia od _somhere_. Zasadniczo jest to inny wątek, który wykonuje wywołanie zwrotne. Możesz uważać usługę "WatchService" za "wywołującego wywołanie zwrotne" ... – fge

+1

fge: Jeśli zajrzysz do hierarchii klas WatchService, zobaczysz, że tylko ogólna usługa PollingWatchService używa naiwnego, zajętego mechanizmu pod maską. Inne usługi zegarków opierają się na funkcjach systemu operacyjnego, które przechwytują zdarzenia bardziej efektywnie - prawdopodobnie tak wydajnie, jak oczekiwanie na przesłanie bajtów do strumienia. Sposób, w jaki projektuje się API usługi Watch, powoduje, że ta korzyść jest ponownie odbierana, gdy aplikacja próbuje odbierać zdarzenia z WatchKey, ponieważ nie ma blokującej metody waitForEvent() lub podobnej. Istnieje olbrzymia różnica między wątkiem bezczynności i zajętości tła. –

+0

"EDYCJA": Zobacz moją odpowiedź na niestosowne podejście, które działa. Mimo to sposób wyjaśniony w Poradniku Java http://docs.oracle.com/javase/tutorial/essential/io/notification.html jest zajęty ... –

Odpowiedz

3

Apache Commons ma kilka usług do przeglądania plików, które moim zdaniem są znacznie lepsze niż te w Javie 7. Nie jestem pewien, czy używają one wywołań zwrotnych, ale są one w moim przekonaniu o wiele bardziej intuicyjne.

I tak, myślę, że model obserwatora byłby o wiele lepszy. Czytałem gdzieś, że nieco trudniej to zrobić z Javą, ponieważ działa ona przez maszynę wirtualną, i aby uzyskać słuchaczy na plikach, które trzeba rozmawiać bezpośrednio z systemem operacyjnym. Nie jestem jednak pewien szczegółów ani ważności tego.

+0

Masz na myśli http: //commons.apache .org/proper/commons-io/javadocs/api-release/index.html? org/apache/commons/io/monitor/package-summary.html? Uruchomiony, który spawns wątek monitorowania wyzwalania dowolnego zarejestrowanego FileAlterationObserver w określonym przedziale. – flup

3

Nie musisz używać odpytywania, możesz użyć funkcji WatchService.take(), która zwraca natychmiast po wystąpieniu zmiany. Tak, wymaga wątku, ale pojedynczy wątek może być używany do oglądania wielu obiektów. Łatwo więc zaimplementować singleton, który jest właścicielem obserwowanego wątku i umożliwia rejestrowanie wywołań zwrotnych dla każdego obiektu.

Jeśli chodzi o biblioteki stron trzecich, spójrz na Guava EventBus. Nie próbowałem tego i nie jestem pewien, czy to pasuje do twoich potrzeb.

+0

nie to robi funkcja WatchService.take(). Zwraca WatchKey, a nie WatchEvent. Co ciekawe, w moim teście na Linuksie, po pierwszej zmianie, którą wywołałem w systemie plików, zwróciło to samo WatchKey, co w Path.register (...). –

+0

"EDYCJA": Zgadzam się z tobą. Zobacz moją odpowiedź dla szczegółów. –

3

buduję na Alexeis odpowiedź, ale nie sądzę, że było wystarczająco jasne ... spojrzeć na ten kod Przykład:

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

Jeśli sprawdzić println(key)/println(k) wyjścia, zobaczysz, że ten sam obiekt jest wielokrotnie zwracany; take() zwraca za każdym razem, gdy klucz jest sygnalizowany, więc aby użyć wielu kluczy z tym samym WatchService, po prostu sprawdź, który klucz został zwrócony za każdym razem. Oznacza to również, że twoja pętla blokuje tak długo, jak długo klucz nie był sygnalizowany - dokładnie to, co chcesz.

the if(!k.reset()) break; również ma kluczowe znaczenie; o tym zapomniałem, pisząc swój komentarz na temat odpowiedzi Alexeisa. Moje założenie było takie, że take() jest wywoływane przez register(), a zatem żaden klucz nie powinien zostać zwrócony w moim kodzie użytkownika, ponieważ register() już go wykorzystał. Z tego błędnego założenia nie wiedziałem, co się właściwie dzieje.