2013-05-17 65 views
1

我有一個課程,可以以不同的速度回放過去的時間。在我下面的示例代碼中,我以60x播放。Java:時間漂移

我注意到時間每隔10秒鐘就會漂移一秒鐘左右,我在想如何處理它。

import java.util.Calendar; 

public class Clock { 

    long delta; 
    long lastCalledTime; 
    long startingTime; 
    private float speed = 1f; 

    public synchronized long getAdjustedTimeMillis() { 
     long time = (System.currentTimeMillis() - (delta)); 
     long val = (startingTime + (long) ((time - lastCalledTime) * speed)); 
     return val; 
    } 

    public synchronized void setPlaybackSpeedFromTime(float speed, long startingTime) { 
     this.startingTime = startingTime; 
     this.delta = System.currentTimeMillis() - startingTime; 
     this.speed = speed; 
     this.lastCalledTime = System.currentTimeMillis() - delta; 
    } 

    public static void main(String[] args) { 
     Calendar calendar = Calendar.getInstance(); 
     calendar.set(2010, 4, 4, 4, 4, 4); 
     Clock clock = new Clock(); 
     clock.setPlaybackSpeedFromTime(60f, calendar.getTimeInMillis()); 
     for (int i = 0; i < 1000; i++) { 
      calendar.setTimeInMillis(clock.getAdjustedTimeMillis()); 
      System.out.println(calendar.getTime()); 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 


    } 

} 

這是我得到的輸出:

Tue May 04 04:04:04 PDT 2010 
Tue May 04 04:05:06 PDT 2010 
Tue May 04 04:06:06 PDT 2010 
Tue May 04 04:07:06 PDT 2010 
Tue May 04 04:08:06 PDT 2010 
Tue May 04 04:09:06 PDT 2010 
Tue May 04 04:10:06 PDT 2010 
Tue May 04 04:11:06 PDT 2010 
Tue May 04 04:12:06 PDT 2010 
Tue May 04 04:13:07 PDT 2010 
Tue May 04 04:14:07 PDT 2010 
Tue May 04 04:15:07 PDT 2010 
Tue May 04 04:16:07 PDT 2010 
Tue May 04 04:17:07 PDT 2010 
Tue May 04 04:18:07 PDT 2010 
Tue May 04 04:19:07 PDT 2010 
Tue May 04 04:20:07 PDT 2010 
Tue May 04 04:21:07 PDT 2010 
Tue May 04 04:22:07 PDT 2010 
Tue May 04 04:23:08 PDT 2010 
Tue May 04 04:24:08 PDT 2010 

正如你可以看到 「秒」 漂移。我想要的是:

Tue May 04 04:04:04 PDT 2010 
Tue May 04 04:05:04 PDT 2010 
Tue May 04 04:06:04 PDT 2010 
Tue May 04 04:07:04 PDT 2010 
Tue May 04 04:08:04 PDT 2010 
Tue May 04 04:09:04 PDT 2010 
Tue May 04 04:10:04 PDT 2010 
Tue May 04 04:11:04 PDT 2010 
Tue May 04 04:12:04 PDT 2010 
Tue May 04 04:13:04 PDT 2010 
Tue May 04 04:14:04 PDT 2010 
Tue May 04 04:15:04 PDT 2010 
Tue May 04 04:16:04 PDT 2010 
Tue May 04 04:17:04 PDT 2010 
Tue May 04 04:18:04 PDT 2010 
Tue May 04 04:19:04 PDT 2010 
Tue May 04 04:20:04 PDT 2010 
Tue May 04 04:21:04 PDT 2010 
Tue May 04 04:22:04 PDT 2010 
Tue May 04 04:23:04 PDT 2010 
Tue May 04 04:24:04 PDT 2010 
+5

嗯,問題很簡單 - Thread.sleep不是一個確切的函數,也沒有考慮處理時間,這會在許多(很多)迭代中累積。不確定如何解決它雖然 – Alex

回答

0

爲什麼不直接使用系統時鐘?

initialStartTime = System.currentTimeMillis(); 
while (true){ 
    if (intialStartTime - System.currentTimeMillis() % 1000 == 0){ 
     System.out.println(calendar.getTime()); 
    } 
} 

顯然,你會想在後臺線程上運行上述代碼,而不是while(true)有一些合理的退出條件。 SO上有很多關於線程的信息。

1

只需將您的時間放在您知道準確的來源上即可...對於臨時應用程序,系統時鐘通常足夠好。如果您嘗試讓您的應用程序帳戶佔用一段時間,那麼您的精度將受到JVM併發魯棒性的限制。而且,老實說,這不是JVM打算做得很好的事情。

+0

事實上,Java是爲不適用於關鍵定時應用程序的常見業務應用程序而構建的。但是,已經嘗試構建專門的[實時Java](http://en.m.wikipedia.org/wiki/Real_time_Java)實現。 –

1

您有時間漂移,因爲您的進程正在進行其他操作時已經過去了一段時間。而不是Thread.sleep(int),請嘗試java.util.Timer.scheduleAtFixedRate(task, date, period)。 Timer在內部計算下一個執行時間並在指定的時間觸發。此觸發也由Timer使用等待通知鎖定機制在內部完成。簡而言之,你必須實現TimerTask來更新Clock,然後使用Timer按照期望的時間間隔(例如1000ms)調度任務。

+0

這實際上保證執行每隔1000毫秒,在MS?或者只是在那個球場上拿點東西? – Alex

+0

沒有保證,定時器可能會「失火」(錯過觸發時機)。這通常發生在沒有大的環境中。的線程和線程池很小。對於通常的情況,時間非常準確。 – happymeal