2016-01-13 13 views
21

デフォルトのjava.time.Clockの実装は、System.currentTimeMillis()に基づいています。ここで例として説明したように、 Monotonically increasing time in Java?、 単調であることは保証されません。Javaに一貫性のある(単調な)クロック実装がありますか?

実際、私は定期的にシステム時間が自動的に数秒前に調整され、Javaクロックもまた戻ってくる状況を経験しています。

//now() returns 2016-01-13T22:34:05.681Z 
order.setCreationTime(Instant.now()); 

//... something happens, order gets cancelled 

//now() returns 2016-01-13T22:34:03.123Z 
//which is a few seconds before the former one, 
//even though the call was performed later - in any reasonable sense. 
//The recorded history of events is obviously inconsistent with the real world. 
order.setCancelationTime(Instant.now()); 

1を一方向にのみに行く時間に頼ることができない場合には、イベントの履歴を記録し、分析するように、その後、時間に敏感な事柄を実行することは不可能です。

上記の投稿では、System.nanoTime()は単調である(基本システムでサポートされている場合)。したがって、私のコードをjava.time APIの基底にしたい場合、時間の一方向の流れを保証するために、内部的にnanoTimeを使用するClockが必要です。このようなものが働くかもしれない。それとも?

public class MyClock() extends java.time.Clock { 

    private final long adjustment; 

    public MyClock() { 
     long cpuTimeMillis = System.nanoTime()/1000000; 
     long systemTimeMillis = System.currentTimeMillis(); 
     adjustment = systemTimeMillis - cpuTimeMillis; 
    } 

    @Override 
    public long millis() { 
     long currentCpuTimeMillis = System.nanoTime()/1000000; 
     return currentCpuTimeMillis + adjustment; 
    } 
} 

単なるスケッチであり、完全なクロック実装ではありません。そして、適切な実装では、currentTimeMillis()に対して直接ではなく、コンストラクタで渡される別のClockに対しても調整を実行する必要があると思います。

または、既にどこでも単調なクロックの実装がありますか?私は、同じ問題に直面している多くの人々がいたに違いないと思います。

結論

感謝の言葉と答えに感謝します。コメントにはいくつかの興味深い点が散見されているので、ここでそれを要約します。私の元の質問については

1.単調クロック

、はい、逆方向にジャンプするシステム時刻に影響されない単調なクロックを持つことが可能です。そのような実装は上記のSystem.nanoTime()に基づいています。過去にこの問題が発生していましたが、現代の現代システムではうまくいくはずです。このアプローチは、すでにTime4Jライブラリに例えば実装され、その単調なクロックを簡単java.time.Clockに変換することができます。

Clock clock = TemporalType.CLOCK.from(SystemClock.MONOTONIC); 

2.適切なシステム時刻制御

それは構成することが可能とITシステム時間管理(unix/linuxのntpd)。システム時間が事実上戻ってこないようにする(必要に応じて遅くなる)ので、システム時間は単調増加に依存し、Javaではclock-magicは必要ありません。

私のアプリはサーバー側であり、私は時間を制御することができるので、私はこのようにします。実際には、自分でインストールした実験環境(ドメインの表面知識のみ)で異常を経験しましたが、ではなく、ntpdateクライアント(時間が同期していない場合は後方にジャンプできます) ntpd(ジャンプバックしないように設定できます)。シーケンスではなく、クロックを使用して

3. 1は、アトミックに生成されたシーケンスからのイベントのシリアル番号を与え、壁に頼らない方が安全であるものを前に何が起こったのか強い関係を追跡する必要がある

クロック。アプリケーションがいくつかのノードで実行されていると、これは唯一のオプションになります(私の場合ではありません)。

+3

時間は単調なものですが、日付はありません。日付は時間を表す人間の構成です。純粋に時間を表現するために何かが必要な場合は、代わりにデータベースシーケンスやその他の信頼できる情報を使用できます。 – Leo

+1

nanoTimeで必要なことを行うことができない場合があります。 http://www.principiaprogramatica.com/?p=16 – Bill

+1

私の[単調時計の実装]のソースを調べることができるかもしれません(http://time4j.net/javadoc-en/net/time4j/SystemClock.html #MONOTONIC)を使用して、いくつかのアイデアをjava.timeベースの時計に転送します。ソース - 参照:https://github.com/MenoData/Time4J/blob/master/core/src/main/java/net/time4j/SystemClock.java –

答えて

3

は、キーが正しい(JVMが実行されます)マシンの時刻同期を持つことです。

あなたはクライアントをプログラムする場合、実際にシステムクロックに依存していることが危険なことができます。 しかし、サーバには解決策があります。厳密な設定でNTPを使用することを検討することをお勧めします。

In here彼らはNTPは時間を遅くし、後方にそれを設定しないことを説明しbasicly。

そしてthis NTP documentationは言う:

はntpdが最初に開始されたときに時々、特に、エラーが 128ミリ秒を超える可能性があります。これにより、ローカルの時計時刻が将来128秒を超えると、サーバーに対する時刻が になる場合があります。一部のアプリケーションでは、この動作は受け入れられない可能性があります( )。 -xオプションがコマンドラインに含まれている場合、 クロックはステップされず、スルー補正のみが使用されます。

3

は、例えば、nanoTimeが単調に増加するが、それは時間を壁にきれいに関連していないことに注意してください。ハイバネーションイベント、VMサスペンションなどに起因します。

そして、あなたも再びあなたをかむことがあり、その後currentMillisに同期する複数のサーバー間で物事を配布開始した場合。

おそらく、あなたのサーバーのシステム時間を制御することを考慮する必要があります。

イベントの相対的な順序を、それらが記録されていた時間とは別に追跡します。の@ the8472が言うように

関連する問題