1

単一のスレッドでいくつかの JUnit テストを実行していますが、非決定的な方法で失敗しています。ある人から、最適化 JVM (Oracle Hotspot 64-Bit 17.1-b03) が命令を順不同で実行していると教えてもらいました。Java仕様でそれが許可されているとは信じられませんが、特定の参照が見つかりません.

ウィキペディアは、単一のスレッドがスレッド内 as-if-serial を強制する必要があると述べているため、私が書いたものと異なる実行順序について心配する必要はありません。 http://en.wikipedia.org/wiki/Java_Memory_Model#The_memory_model

コード例:

@Test
public void testPersistence() throws Exception
{
    // Setup
    final long preTestTimeStamp = System.currentTimeMillis();

    // Test
    persistenceMethod();

    // Validate
    final long postTestTimeStamp = System.currentTimeMillis();
    final long updateTimeStamp = -- load the timestamp from the database -- ;
    assertTrue("Updated time should be after the pretest time", updateTimeStamp >= preTestTimeStamp);
    assertTrue("Updated time should be before the posttest time", updateTimeStamp <= postTestTimeStamp);
}

void persistenceMethod()
{
    ...
    final long updateTime = System.currentTimeMillis();
    ...
    -- persist updateTime to the database --
    ...
}

このテスト コードを実行すると、完全に非決定論的な動作をします。成功する場合もあれば、最初のアサートで失敗する場合もあれば、2 番目のアサートで失敗する場合もあります。値は常に互いに 1 ~ 2 ミリ秒以内であるため、永続化が完全に失敗しているわけではありません。Thread.sleep(2); の追加 各ステートメントの間にテストが失敗する回数は減りますが、失敗を完全に排除するわけではありません。

これは JVM の障害である可能性がありますか、それともデータベース (MsSql) が格納されたデータの何らかの丸め処理を行っている可能性が高いですか?

4

3 に答える 3

0

mySql (0r 永続化コード) が何かを行っているかどうかを判断するのは簡単なはずです。persistenceMethod() に永続化された値を返させ、読み取った値と比較します。きっと一致するはずです。

問題になっているのは currentTimeMillis() の信頼性であるかどうか疑問に思います。

現在の時刻をミリ秒で返します。戻り値の時間単位はミリ秒ですが、値の粒度は基盤となるオペレーティング システムに依存し、それよりも大きい場合があることに注意してください。たとえば、多くのオペレーティング システムでは、時間を数十ミリ秒単位で測定します。

あなたが >= テストを行っていることを考えると、それがどのように現れるかはよくわかりませんが、正確に何回取得しているのか疑問に思います.

于 2011-07-11T20:46:19.123 に答える
0

それは本当に奇妙です。Java は、それらのステートメントに後続のステートメントに影響を与える副作用がある場合、ステートメントを並べ替えたり、別の順序で実行したりすることはありません。

System.currentTimeMillisはあなたが思っているほど正確ではないため、このエラーが発生すると思います。そのメソッドの API ドキュメントには次のように書かれています。

現在の時刻をミリ秒で返します。戻り値の時間単位はミリ秒ですが、値の粒度は基盤となるオペレーティング システムに依存し、それよりも大きい場合があることに注意してください。たとえば、多くのオペレーティング システムでは、時間を数十ミリ秒単位で測定します。

奇妙に聞こえるかもしれませんが、場合によっては時間が逆行しているように見えることもあるため、あるcurrentTimeMillis瞬間に返される値は、その瞬間前に返された値よりも低くなる可能性があります。この質問を参照してください: System.currentTimeMillis は常に値 >= 以前の呼び出しを返しますか?

于 2011-07-11T20:46:58.713 に答える