2011-08-13 11 views
10

のは、誰かがintを返すメソッドを同期化し想像してみましょう:javaは不要な同期文を削除/最適化しますか?

int whatever = 33; 
... 

public synchronized int getWathever() { 
    return this.whatever; 
} 

は、我々はint型がアトミックに変更されたJava仕様から知っています。したがって、​​ステートメントは必要ありません。

コンパイラはそれを削除/最適化しますか?

+2

あなた(プログラマー)がそれを不要なものとして認識するのはなぜですか? – Hyperbole

+2

私はしませんが、私がサードパーティ製のコードに依存しているとします。 – JVerstry

答えて

7

なしを取得することにより確保するのが最も簡単であり、変数のロード中に他のスレッドによって保持されていないことを確認しなければならないにもかかわらず。コンパイラとJVMがそうする場合は、Javaプログラミング言語のメモリモデルによって設定された制約に違反する可能性があります。

具体的には、Java言語仕様に記載されているsynchronization orderの順番に違反します。コンパイラまたはJVM *が「不要な」同期を削除した場合、実行されるそれ以上の最適化は、開発者が同期順序(およびhappen-before)関係で行った仮定に違反します。具体的には、Javaメモリモデルに従うコンパイラ/ JVMで、読み込みの前に整数への書き込みが行われます。

シンクロナイゼーションを削除するコンパイラ/ JVMは、単にメモリモデルに違反する環境になります。たとえば、コンパイラ/ JVMが整数値の読み込みの前にメモリバリアを置かずに、キャッシュされた値から古い値を読み取ることができるように、メソッドのインライン展開を実行できます。

*コンパイラ/ JVMデュオへの参照は意図的です。コンパイラは、JLSに準拠するバイトコードのみを出力します。 JVMは単にメモリモデルの要件に違反するバグを持つ可能性があります。メモリモデルを完全にするために、コンパイラとJVMの両方がメモリモデルによって設定された要件に準拠する必要があります。

+0

この回答は基本的にラチェットフリークのものと同じですが、私はそれが行動をより明確にすると思います。 – Voo

+0

HotSpot 1.6以降も可能です。しかし、それはJavaコンパイラによって削除されるのではなく、JITコンパイラによって削除されます。 HotSpot JVM 1.6以来、 'StringBuffer'や' Hashtable'と 'StringBuilder'や' HashMap'の不必要な同期化がシングルスレッドで使用された場合のパフォーマンスの低下は最小限に抑えられていることが文書化されています。 http://www.ibm.com/developerworks/java/library/j-jtp10185/ – Oliv

4

int変数が何らかの方法でメインメモリに正しく同期されていることを保証しない限り、スレッドセーフであることを意図している場合は、 "synchronized"を削除することは絶対に安全ではありません。同期

+0

しかし、私が間違っていない限り、longとdoubleへの変更だけにvolatileが必要ですか? – JVerstry

+5

シングルコアプロセッサでこのプログラムを実行する場合を除き、いいえ。それは原子の書き込みと読み取りについてではありません。それはCPUキャッシュとメインメモリの間で前後に転送される値に関するものです。複数のスレッドが動作し、「同期」していないマルチコアマシンでは、各コアは他のスレッドとメインメモリとで異なる値を持つので、異なるスレッドが同じ変数に対して異なる値を示す可能性があります。 –

7

は、(1のために他のスレッドに表示されている変更されたデータを確実に)ロックを取得以外に、他のスレッドの安全性の効果を持っている

限り、これらの副作用は、JITは、それが

を望んでいるものを行うために、基本的に自由である有効であるとして、

例では、ロックが単に可能ではないことを、効果的にロック

+1

最初の文はここで重要な部分です。同期化は、オブジェクトの**任意の**メソッドの後続の呼び出しとの間に、先行関係を保証します。同期を削除すると、ここでの動作が変更されます。 – Voo

+0

ジャンプポイント。それは理にかなっている。 – JVerstry

5

VMがロックを解除できる場合があります。例えば

エスケープ解析

int bar() 
    Foo foo = new Foo(); 
    return foo.getWhatever(); 

VMはgetWhatever方法のtherforeロックをドロップすることができ、したがって、誰もがそれをロックしようとしないだろう、そのfooは、他のスレッドに表示されていない理由ができます。

ロック粗大

Foo foo = ...; 
void bar() 
    a(); 
    foo.getWhatever(); 
    b(); 
    foo.getWhatever(); 
    c(); 

が法的にロックされた領域は、そう、短い適応ロックによる、VM最も可能性の高い意志であるので、もう一つの良いニュースがある1つのロック作用

void bar() 
    synchronized(foo) 
     a(); 
     foo.getWhatever_without_lock(); 
     b(); 
     foo.getWhatever_without_lock(); 
     c(); 

を節約するためにマージすることができ

スピンロックを使用します。ロックの失敗によるスレッドの中断はほとんどありません。

+0

を参照してください。これについての参考資料はありますか? –

+0

@ RyanちょうどGoogleの用語 – irreputable

+0

も参照してくださいhttp://stackoverflow.com/questions/18996783/what-is-the-synchronization-cost-of-calling-a-synchronized-method-from-a-synchro – Raedwald

関連する問題