2012-01-28 30 views
17

Używał Java Timer, a następnie przełączono na ScheduledExecutorService, ale mój problem nie został naprawiony. Jako zadania zaplanowane przed zmianą czasu systemowego (przez ntpd) nie są wykonywane po określonym opóźnieniu. Nie mają dzienniki samo jak nic się nie dzieje :(Harmonogram Java, który jest całkowicie niezależny od zmian czasu systemowego

użyciu jre 1.6.0_26 64 bit w moim celem na 64 bitowym systemie Linux

Aktualizacja:... ScheduledExecutorService działa poprawnie na Windows Problem polega tylko na 64-bitowy Linux system oparty systemem 64 bitowym JVM. współpracuje na 64 bitowym systemem Linux 32 bit JVM ... dziwne. nie znaleziono żadnych odniesienie takie same na wszystkich blogach albo.

IBM Java SDK ma ten sam problem (ibm-java-sdk-7.0-0.0-x86_64-archive.bin) .

I złożył wadę przeciwko JDK 7139684, było akceptowane, ale został zamknięty i oznaczone duplikat 6900441. Proszę głosować na niego, jeśli czujesz warto aby to naprawić ... Nie mam pojęcia, dlaczego jej nie został ustalony od ponad kilku lat

Oto przykładowy kod kiedyś przetestować ten problem :

package test; 

import java.io.IOException; 
import java.util.Date; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ScheduledExecutorService; 
import java.util.concurrent.TimeUnit; 

/** 
* @author yogesh 
* 
*/ 
public class TimerCheck implements Runnable { 

    ScheduledExecutorService worker; 


    public TimerCheck(ScheduledExecutorService worker) { 
     super(); 
     this.worker = worker; 
     this.worker.schedule(this, 1, TimeUnit.SECONDS); 
    } 

    private static void update() { 
     System.out.println("TimerCheck.update() "+new Date(System.currentTimeMillis())); 
    } 

    @Override 
    public void run() { 
      update(); 
      worker.schedule(this, 1, TimeUnit.SECONDS); 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     ScheduledExecutorService worker = Executors.newScheduledThreadPool(1); 
     new TimerCheck(worker); 
    } 

} 
+1

Ten przykładowy kod działa poprawnie na moim komputerze Ubuntu 11.10 [32-bitowy], JVM 1.6.0_21 [32-bitowy]. Zmiana zegara systemowego nie wpływa na wykonanie. – Gopi

+0

tak również sprawdził, czy działa poprawnie na 64-bitowym linuksie z 32-bitowym jvm :(odpowiednio zaktualizował moje pytanie – YoK

+1

Chciałbym tylko wskazać, że określanie nanosekund jest w tym przypadku bez znaczenia. Wewnętrznie, kod zmienia się na millis. Tak więc 'employee.schedule (this, 1000000000, TimeUnit.NANOSECONDS);' jest identyczne z 'worker.schedule (this, 1, TimeUnit.SECONDS);' –

Odpowiedz

7

Istnieje bug in JVM dla ogólnego planowania w czasie zmian czasu Sytemu w tył, co ma również wpływ na bardzo podstawowe metody Object.wait & Thread.sleep. Stwarzanie aplikacji Java staje się zbyt ryzykowne, gdy czas systemowy przełącza się nawet o kilka sekund. Nigdy nie wiesz, do czego dojdzie Twoja aplikacja Java.

Więc zdecydowaliśmy się:

  • Zapis Watch Dog skryptu (nie Java :)), aby sprawdzić zmiany czasu.
  • jeśli czas przełączy się o określoną kwotę, zamknij i uruchom ponownie aplikację Java.

Inną możliwością było przejście na 32-bitową maszynę JVM, ale używamy JNI, a następnie biblioteki natywne używane na platformie docelowej nie są kompatybilne z 32-bitową. Również z naszego doświadczenia wynika, że ​​32-bitowa maszyna JVM ogranicza nasz cel do sterty 1,6G, co wcale nie jest dla nas wystarczające.

Wiem, że nasze rozwiązanie nie jest najbardziej eleganckie, ale dopóki JVM nie zostanie naprawione lub znajdzie się jakieś lepsze rozwiązanie, nie wydaje się, żeby był jakikolwiek inny sposób.

Zmieniano: Rozważamy również 1st sugestię Chris oprócz powyższego roztworu:

  • Konfiguracja NTP, aby nigdy nie mają czasu wielki skok. Pokonał czas tylko powoli: . Skoki w czasie należy wykonywać tylko ręcznie.
+0

Zaakceptowanie tej odpowiedzi jako obejścia :(Wciąż czekając na właściwe rozwiązanie – YoK

+0

Nie rozumiem, jak bardzo wpływa to na maszynę JVM. Z twojego problemu wydaje się, że jest to krytyczny błąd, na przykład jeśli użyję Object.wait (1), a zegary cofną się - czy to oznacza, że ​​wątek nigdy nie zostanie przebudzony? – BegemoT

+0

@BegemoT To nie znaczy, że nigdy się nie obudzi ...Ale obudzi się po (przesunięcie zegara czasu + 1). który jest niebezpieczny. I to tylko dzieje się na 64-bitowej maszynie JVM na 64-bitowym Linuksie. – YoK

2

Pracowałem przeciwko temu samemu problemowi i nie znalazłem rozwiązania. Spojrzałem na Quartz i wszystkie wbudowane metody JRE. Metody nanotime mogą wykorzystywać monotoniczne zegary na jednostkę CPU, ale ryzykujesz duże skoki, jeśli wątki są migrowane do innego procesora, jak sądzę. Moje wnioski były następujące:

  1. Skonfiguruj NTP tak, aby nigdy nie miał dużego skoku w czasie. Wolno tylko zabijać czas. Skoki w czasie należy wykonywać tylko ręcznie.
  2. Użyj kilku krótszych limitów czasu i zażądaj dwóch limitów czasu, aby zadeklarować zdalną maszynę. To nie pomoże, jeśli masz tylko jeden czas systemowy, ale może pomóc w wielu systemach, aby celowo używać komputera zdalnie do wysyłania okresowych wyborów. Jeśli twój zegar cofa się pomiędzy przebudzeniami, to wiesz, że wszyscy twoi zegary będą strzelać późno.

Zasadniczo jest to ogromny ból, ale nie ma srebrnych kul.

+0

Ale czy ostatecznie zastosowałeś któreś z tych rozwiązań, dla mnie są to niemożliwe :) – YoK

+2

@YoK, tak, wszystkie trzy. wykrywał, czy/kiedy zginęła główna usługa, więc kopia zapasowa może automatycznie przejąć kontrolę. We wszystkich konfiguracjach NTP, których używałem, zachowanie było następujące: jeśli synchronizacja trwa w ciągu N minut (powiedzmy 2), powoli powoluj zegar w odpowiednim czasie z prędkością X milis na minutę (powiedzmy 20). Jeśli synchronizacja jest dłuższa niż N minut, NTP wydaje komunikat ostrzegawczy systemu o błędzie i przechodzi w tryb pasywny. –

+0

Interesujące ... poprosi moich facetów NTP, aby spojrzeć na to. – YoK