目次
質問内容
解決策
...但我需要单调递增的时间戳!
currenttimemillis
nanotime
问题
ホームページ Java 大きな時間枠で計算された経過時間が、System.currentTimeMillis と System.nanoTime で最大 100 ミリ秒以上異なるのはなぜですか

大きな時間枠で計算された経過時間が、System.currentTimeMillis と System.nanoTime で最大 100 ミリ秒以上異なるのはなぜですか

Feb 09, 2024 am 10:24 AM
overflow

php エディター Apple は、大きな時間枠で計算された経過時間が System.currentTimeMillis と System.nanoTime で最大 100 ミリ秒異なる理由を説明します。この問題には、コンピュータ システムの基礎となるメカニズムとオペレーティング システムのスケジューリング方法が関係します。経過時間を計算するとき、System.currentTimeMillis はオペレーティング システムによって提供される実時間を使用しますが、System.nanoTime は CPU クロック サイクルを使用します。オペレーティング システムのスケジューリング メカニズムとハードウェア クロックの非同期性により、これら 2 つのタイミング方法では時間差が生じます。具体的な原因と解決策は以下の記事で詳しく紹介しています。

質問内容

同じjvmでマイクロ秒の歳差ソートができるksuidを作成しようとしています。currenttimemillisはミリ秒の精度しか与えないため、currenttimemillis()とnanotime()を一緒に使用することを検討してください。 、最初の瞬間から経過したマイクロ秒数のナノタイム差は、最初の瞬間と 2 番目の瞬間から始まる値を収集することによって計算されます。ナノタイムから計算された経過時間を使用し、それを最初の瞬間のミリ秒に追加します。これにより、jvm の開始後の任意の瞬間に (すべて同じ jvm 内で) エポックをマイクロ秒の精度で計算できます。

//初期ナノタイムと現在のミリスの静的コレクション 最終の長い inittimenanos = system.nanotime(); 最終の長い inittimemillis = system.currenttimemillis();

//今後、マイクロ/ナノ秒精度の現在時刻が必要な場合は、ナノタイムから経過時間を計算し、経過ミリ秒を初期ミリ秒に加算し、残りの経過時間でマイクロ秒精度の時刻を求めます

final long elapsednanotime = system.nanotime() - inittimenanos;final double elapsedmillisfromnanotime = elapsednanos / (1000000.0);

//jvm が開始されてから単調に増加するタイムスタンプ ミリ秒 (エポック、エポックとは呼ばないかもしれません) 最終の長い計算現在時間ミリス = inittimemillis elapsedmillisfromnanotime; 最終的な長いナノ精度 = elapsednanos % 1000000; //ナノタイムからの追加の時間精度

これらの値を使用して単調増加する ksuid を生成することを検討してください。これは現在時刻を近似できますが、同じ jvm 内の作成時刻に従ってソートされることが保証されています。currenttimemillis は単調増加するタイムスタンプ保証を提供していないため、考慮してください。このメソッドを使用して、実際のタイムスタンプにほぼ近い単調増加タイムスタンプ (エポック タイムにうるう秒の調整が行われない限り、数ミリ秒異なる可能性があります) を生成します。エポックとナノタイムを使用して計算された経過時間は数ミリ秒異なることが予想されていましたが、実際の差は非常に頻繁に変化し、以下のテストを 48 時間実行したところ、両者の間に最大 150 ミリ秒の差が観察されました。ほとんどの場合、nanotime を使用して計算された経過時間は、currenttimemillis を使用して計算された経過時間よりも長く、観測される時間の範囲は -2 ミリ秒から 150 ミリ秒の範囲です。

Final long elapsedmillis = system.currenttimemillis() - inittimemillis; //system.currenttimemillis() からの経過時間ミリ秒 最後の二重差 millis = elapsedmillisfromnanotime - elapsedmillis; //経過時間分散

JVM のタイミング保証について何か見逃していますか? 単調増加する近似タイムスタンプを計算する方法が間違っていますか? (これはシステム内の実際のエポックとしては使用されず、同じ jvm 内のおおよそのタイムスタンプの瞬間も表す uuid を生成するためだけに使用されます)。

//テストクラス

リーリー

経過時間の差異が変化し続けるのはなぜですか? jvm を 1 年間継続的に実行した場合に予想できる最大分散はどれくらいですか (どの jvm もこの上限または下限を保証しており、Mac と Windows でテストしましたが、Mac では分散の増加が遅く、Windows ははるかに高速でした)。

経過時間の変動は 10 ミリ秒未満であり、変更の発生頻度は低いと予想します。 しかし、実際の観察では、分散は常に変化しており、上下に変動しており、48 時間以内に最大 150 ミリ秒が観察されています。

解決策

説明の 1 つは、ntp に基づく時間スミアリングです。より一般的には、nanotime と ctm はまったく異なるものを測定するため、それらを混合することはできません。

nanotime には任意の 0 点があります (nanotime が 0 になることには特別な意味はありません)。そのため、返される内容をさまざまな nanotime 呼び出しの結果と比較する以外に、これを呼び出す必要はまったくありません。 nanotime は経過時間を追跡する、それだけです。

system.ctm システムクロックを取得します。 posix date コマンドを使用するか、システム設定でシステムの時刻設定を編集する場合、これは nanotime には影響しませんが、system.ctm が返す内容は変更されます。また、ctm は通常、nanotime よりもはるかに遅いです。 ctm には、1970 年 1 月 1 日の UTC 午前 0 時を表す、明確に定義された 0 もあります。

問題: 「現在時刻をナノ秒の精度でシステムクロックと一致させたい」は、JVM では 不可能です。

时间涂抹是指某些网络时间守护程序注意到您的系统时钟略有偏差,并且不只是将系统时钟编辑到正确的时间,而是引入了涂抹:假设您比实时时间“提前”了 400 毫秒。 ntp 可以将您的时钟向后设置 400 毫秒,但许多日志记录系统假设 system.ctm 不会向后移动(这是一个不正确但广泛应用的假设)。

这可以通过让时间放慢一段时间来“修复”:每经过 100 毫秒,ntp 守护进程就会将时钟“保持”在同一毫秒上一毫秒。每 100 毫秒就赶上 1 毫秒,因此在 400,000 毫秒(仅 400 秒)内,时钟恢复与网络同步,并且日志记录根本不受影响。

但是,这显然会完全破坏 system.ctm 和 nanotime 之间的任何关系!

大多数 ntp 都是这样涂抹的(它们也会向前涂抹 - 如果您的系统时钟落后,它不仅仅会向前跳跃:这会使日志撒谎(使其看起来就像两个事件之间存在一些间隙)比实际大得多),因此每 100 毫秒,ntp 就会使时钟跳过一毫秒,类似这样的事情,以赶上。

...但我需要单调递增的时间戳!

那么 nanotime 就无关紧要了。不要使用它。

拥有一些提供 id 的集中“商店”。一种实现:

class TimeStore {
  long lastVal = 0L;

  public synchronized long get() {
    long mark = System.currentTimeMillis() << 4;
    return lastVal = Math.max(mark, lastVal + 1);
  }
}
ログイン後にコピー

这将返回当前时间,左移 4 位,并将填充此移位“释放”的 16 个值,以便能够在同一时间生成单调递增值,最多 16 次;同一毫秒内的任何进一步请求都会潜入下一毫秒。

尽管如此,这可能并不比nanotime慢。

rzwitserloot的回答是正确的。我将向您提供我对各种问题的看法。

currenttimemillisnanotime 无关

system.currenttimemillissystem.nanotime 彼此无关。

  • currenttimemillis 从主机的硬件时钟单元检索当前日期和时间,由主机操作系统管理。
  • nanotime 来自主机 cpu 保存的计数。

currenttimemillis

所以首先要了解人类的年月日和时分秒的概念。传统计算机中使用的时钟硬件的分辨率有限,有些是毫秒,有些是微秒,但没有纳秒。

由于各种原因,本次通话报告的日期和时间可能会有所不同。其中一个原因是,在电池电量耗尽的情况下启动的计算机会将其时钟重置为默认时刻,直到通过调用时间服务器进行纠正。另一个原因是系统管理员或用户可能会更改日期时间。还有一个原因是硬件时钟可能无法很好地保持时间,并且会通过调用时间服务器在更新之间运行得快或慢。

nanotime

nanotime 调用以纳秒计数形式告知经过的时间。但这个流逝的时间与日历和墙上的时钟无关。此调用仅返回经过的纳秒的单调计数。

这个计数非常准确,因为它来自计算机的“跳动的心脏”。返回的数量始终在增加,直到达到 long.max_value,然后环绕到 long.min_value。这给出了大约 292 年的范围,但这并不意味着从现在起 292 年。计数的起点未指定。在某些 java 实现中,您可能会看到计数在计算机启动时开始。但并不能保证这一点。

问题

您可能会考虑寻找 新 6、7、8 版本 的实现a href="https://en.wikipedia.org/wiki/universally_unique_identifier" rel="nofollow noreferrer">uuid 被提议给 ietf 进行标准化。

currenttimemillis 在现代 java 中已被 java.time.instant 类取代。调用 instant.now 捕获 utc 中的当前时刻。

java 9+ 中的常见实现以微秒为单位报告,但在 java 8 中以毫秒为单位。 instant 类能够以纳秒为单位。

賢いアイデア。しかし、それは現実的ではありません。上で述べたように、currenttimemillisnanotime には関連性がありません。要するに、currenttimemillis の結果はさまざまな理由で異なる可能性があるということです。また、nanotime カウントはホスト マシンが起動するたびに変化する可能性があり、他のマシンで行われた nanotime 呼び出しには対応しません。

はい、あなたは Java 仕様があなたが想定しているような保証をまったく行っていないという事実を無視しています。

javadoc での唯一の保証は、nanotime が「高解像度」であり、少なくとも currenttimemillis と同等であることです。そして、292 年の終わりがいつになるかという保証はありません。

同時に、currenttimemillis は、前進または後進でいつでも変化する可能性がある移動ターゲットです。

これは予測不可能です。

Java 仕様ではそのような保証はありません。

以上が大きな時間枠で計算された経過時間が、System.currentTimeMillis と System.nanoTime で最大 100 ミリ秒以上異なるのはなぜですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

2009 年から 2025 年の誕生以来のビットコインの価格 BTC 過去の価格の最も完全な概要 2009 年から 2025 年の誕生以来のビットコインの価格 BTC 過去の価格の最も完全な概要 Jan 15, 2025 pm 08:11 PM

2009 年の誕生以来、ビットコインは暗号通貨の世界のリーダーとなり、その価格は大きな変動を経験しました。包括的な歴史的概要を提供するために、この記事では 2009 年から 2025 年までのビットコイン価格データをまとめ、主要な市場イベント、市場センチメントの変化、価格変動に影響を与える重要な要因を取り上げます。

ビットコインの誕生以来の歴史的な価格の概要。ビットコインの歴史的な価格動向を完全にまとめています。 ビットコインの誕生以来の歴史的な価格の概要。ビットコインの歴史的な価格動向を完全にまとめています。 Jan 15, 2025 pm 08:14 PM

暗号通貨としてのビットコインは、その誕生以来、市場の大きな変動を経験してきました。この記事では、読者がビットコインの価格傾向と重要な瞬間を理解できるように、誕生以来のビットコインの歴史的な価格の概要を提供します。ビットコインの過去の価格データを分析することで、その価値に対する市場の評価やその変動に影響を与える要因を理解し、将来の投資決定の基礎を提供することができます。

ビットコインBTC歴史的価格動向チャートの誕生以来の歴史的価格のリスト(最新の要約) ビットコインBTC歴史的価格動向チャートの誕生以来の歴史的価格のリスト(最新の要約) Feb 11, 2025 pm 11:36 PM

2009年の作成以来、ビットコインの価格はいくつかの大きな変動を経験し、2021年11月に69,044.77ドルに上昇し、2018年12月に3,191.22ドルに減少しました。 2024年12月の時点で、最新の価格は100,204ドルを超えています。

2018-2024 USDのビットコインの最新価格 2018-2024 USDのビットコインの最新価格 Feb 15, 2025 pm 07:12 PM

リアルタイムのビットコインUSD価格 ビットコインの価格に影響を与える要因 将来のビットコイン価格を予測するための指標 2018年から2024年のビットコインの価格に関する重要な情報を次に示します。

CSSを介してサイズ変更シンボルをカスタマイズし、背景色で均一にする方法は? CSSを介してサイズ変更シンボルをカスタマイズし、背景色で均一にする方法は? Apr 05, 2025 pm 02:30 PM

CSSでサイズ変更シンボルをカスタマイズする方法は、背景色で統一されています。毎日の開発では、調整など、ユーザーインターフェイスの詳細をカスタマイズする必要がある状況に遭遇することがよくあります...

CSSのクリップパス属性を使用して、セグメルターの45度曲線効果を実現する方法は? CSSのクリップパス属性を使用して、セグメルターの45度曲線効果を実現する方法は? Apr 04, 2025 pm 11:45 PM

セグメントターの45度の曲線効果を達成する方法は?セグメンテーションデバイスを実装する過程で、左ボタンをクリックすると、適切な境界線を45度の曲線に変える方法とポイント...

H5ページの生産はフロントエンド開発ですか? H5ページの生産はフロントエンド開発ですか? Apr 05, 2025 pm 11:42 PM

はい、H5ページの生産は、HTML、CSS、JavaScriptなどのコアテクノロジーを含むフロントエンド開発のための重要な実装方法です。開発者は、&lt; canvas&gt;の使用など、これらのテクノロジーを巧みに組み合わせることにより、動的で強力なH5ページを構築します。グラフィックを描画するタグまたはJavaScriptを使用して相互作用の動作を制御します。

フレックスレイアウトの下のテキストは省略されていますが、コンテナは開かれていますか?それを解決する方法は? フレックスレイアウトの下のテキストは省略されていますが、コンテナは開かれていますか?それを解決する方法は? Apr 05, 2025 pm 11:00 PM

フレックスレイアウトとソリューションの下でのテキストの過度の省略によるコンテナの開口部の問題が使用されます...