2

私はJavaスレッドに不慣れで、最近メモリモデルを読み始めたばかりです。私の理解では、現状のJavaメモリモデルにより、コンパイラは最適化を行うことができます。

これはマルチスレッドコードと同期を複雑にする可能性がありますが、私の質問はもっと単純なものです。2つのステートメントは相互に依存していないため、この例を見てください。コンパイラがtryステートメントのコードの順序を変更して、チェックを破る可能性はありますか?

boolean success = false;
try{
 MyClass.someFunction();
 success = true;
}
catch(Exception e){

}

if(success){    
    System.out.println("Sucess!");
}
else{
    System.out.println("Fail!");
}
4

2 に答える 2

4

いいえ。Javaコンパイラは、期待どおりの処理を実行する必要があります。正常に返され、例外が発生した場合Success!はprintを実行します。これは一般的なJavaのセマンティクスに由来し、コンパイラーが行う可能性のあるコンパイラーの最適化とは無関係です(どの最適化が合法であるかを制約する場合を除く)。Myclass.someFunction()Fail!

その理由は、Java言語仕様では、単一のスレッド内で、プログラムはステートメントが上から下に順番に実行されたかのように正確に動作する必要があると規定されているためです。コンパイラは、バイトコードを生成するために、あらゆる種類の直感的でない方法でプログラムを自由に書き直すことができますが、単一のスレッド内で、ソースコードに入力したステートメントを正しい順序で正確に実行しているという錯覚を維持する必要があります。

Java言語仕様は、それをマルチスレッドコンテキストにも拡張でき、すべてのスレッドは、入力したソースコードを正確に実行するすべてのスレッドと一致する世界の状態を常に確認する必要があると述べています。ただし、(a)正しいコンパイラ最適化を書くことを非常に難しくし、そうでなければ有用な最適化の多くは違法になります。(b)とにかく適切な同期の必要性を排除しないので、プログラマーにはあまり役に立ちません。ほとんどの場合、壊れたプログラムを明らかに壊れていないプログラムに変えるだけです。

代わりに、Javaメモリモデルは、あるスレッドのメモリ変更が他のスレッドに表示される場合の正確なルールを定義し、コンパイラがそれ以外の場合に必要なことを実行できるようにします。これは、プログラマーにマルチスレッドプログラムが正しいことを確認するために使用できる一連のルールを提供すると同時に、コンパイラーの作成者に適切な最適化を実装する余地を与えるため、適切な妥協案です。

しかし、あなたの質問の重要なポイントは、コンパイラは舞台裏でやりたいことを何でもできるということですが、プログラムの意味を変更することは許可されていません。シングルスレッドのコンテキストでは、プログラムの意味は明確に定義されており、コンパイラーが考えていた悪いことを実行することはできません。

于 2010-11-08T05:17:07.923 に答える
2

Javaは何をするのか理解できないためMyClass.someFunction()、このステートメントを安全に並べ替えることはできません。実際、ほとんどのデータ依存性チェッカーは、副作用のために関数の境界の外に移動することは完全にできません。

スレッドは特殊なケースであり、Javaに固有のものではありません。データは最終的にレジスタに格納され、必要な場合を除いてメモリから再フェッチされません。Javaのソリューションはtransientキーワードです(volatile他の言語と同様)。

于 2010-11-08T04:13:39.897 に答える