13

コードに 2 つのスレッド (A と B) があり、どこかにこのクラスの同じインスタンスへの参照があるとします。

public class MyValueHolder {

    private int value = 1;

    // ... getter and setter

}

スレッド A がmyValueHolder.setValue(7)を実行した場合、スレッド B がその値を読み取るという保証はありませmyValueHolder.getValue()1

ただし、実際には、ハードウェアは遅かれ早かれ第 2 レベルのキャッシュをクリアするため、スレッド B は7遅かれ早かれ (通常はより早く) 読み取りを行います。

1JVMがスレッド B に永遠に戻り続けるという最悪のシナリオをエミュレートする方法はありますか? このような状況下で、既存のテストを使用してマルチスレッド コードをテストするのに非常に役立ちます。

4

7 に答える 7

2

私は以前、メモリー・モデル・リストでテスト目的で JVM を動作させる最悪のケースを提案しましたが、そのアイデアは人気がないようでした。

したがって、既存のテクノロジーを使用して「最悪の場合のJVM動作」を実現する方法、つまり、問題のシナリオをテストして毎回失敗させるにはどうすればよいですか。可能な限り最も弱いメモリ モデルでセットアップを見つけようとすることもできますが、それが完璧である可能性は低いです。

私がよく考えてきたのは、分散型 JVM を使用することです。これは、Terracotta がカバーの下で動作すると私が信じている方法に似ているため、アプリケーションは複数の JVM (リモートまたはローカル) で実行されます (同じアプリケーションのスレッドは異なるインスタンスで実行されます)。このセットアップでは、JVM スレッド間通信がメモリ バリアで行われます。たとえば、バグのあるコードで欠落している同期キーワード (Java メモリ モデルに準拠している) があり、アプリケーションが構成されています。つまり、このクラス スレッドはここで実行されます。構成だけでテストにコード変更は必要ありません。適切に順序付けされた Java アプリケーションはそのまま実行する必要がありますが、このセットアップは、順序付けが不適切なアプリケーションには非常に不寛容です (通常は問題です...現在は資産、つまりメモリ モデルは非常に弱いが合法的な行動)。setValueは、コードが変更され、同期されたり、揮発性などが使用されたりしない限り、他のスレッドに影響を与えません。その後、コードは意図したとおりに機能します。

上記の例 (正しく構成されている) のテストは、テストに非常に役立つ可能性のある正しい「注文前に発生する」ことがないと、毎回失敗します。完全にカバーするための計画の欠陥は、アプリケーション スレッドごとに 1 つのノード (同じマシンまたはクラスター内の複数のマシン) または複数のテスト実行が必要になる可能性があります。数千のスレッドがある場合、それは法外なものになる可能性がありますが、うまくいけば、それらはプールされ、E2E テスト シナリオ用に縮小されるか、クラウドで実行されます。この種のセットアップは、問題を実証するのに役立つ場合があります。

JVM 間のスレッド間通信

于 2014-08-18T15:43:30.307 に答える
2

残念ながら、実際のマシンではなく、マルチスレッド コードをテストすることは依然として困難です。

あなたが言うように、ハードウェアは第 2 レベルのキャッシュをクリアし、JVM はそれを制御できません。JSL は何が起こらなければならないかを指定するだけで、これはの更新された値が表示されB ない可能性があるケース ですvalue

実際のマシンでこれを強制的に発生させる唯一の方法は、テスト戦略を無効にするような方法でコードを変更することです。つまり、別のコードをテストすることになります。

ただし、第 2 レベルのキャッシュをクリアしないハードウェアをシミュレートするシミュレーターでこれを実行できる場合があります。大変な努力のように聞こえますが!

于 2013-07-11T09:39:25.600 に答える
-2

これは簡単な方法です: のコードをコメントアウトするだけですsetValue。テスト後にコメントを外すことができます。このような多くの場合、失敗を偽造するメカニズムが必要になるため、そのようなすべてのケースに対応する一般的なメカニズムを構築することをお勧めします。

于 2013-07-21T05:12:08.980 に答える