Javaキーワードvolatileとsynchronizedの役割と違い


volatileは変数の修飾子であり、synchronizedはコードまたは方法の一部に作用します。以下の3つのgetコード:

int i1;
int geti1() {return i1;}

volatile int i2;
int geti2() {return i2;}

int i3;
synchronized int geti3() {return i3;}


geti 1()は、現在のスレッドに格納されているi 1の値を得る。複数のスレッドには複数のi 1変数のコピーがあり、これらi 1間は互いに異なることができる。言い換えれば、他のスレッドはスレッド内のi 1値を変更しているかもしれないが、この値は現在のスレッド内のi 1値とは異なることができる。Javaメモリモデルには、Main memory(メインメモリ領域)があり、ここに変数の現在の「正確な値」が格納されています。各スレッドにも独自のmemory(例えばレジスタ)があります。パフォーマンスのために、スレッドは自分のメモリにアクセスする変数のコピーを保存します。このように、同じ変数がある瞬間、スレッドのmemoryの値が他のスレッドmemoryの値、またはmain memoryの値と一致しない場合があります。したがって、実際には、Main memoryの値i 1が1であり、スレッド1のi 1が2であり、スレッド2のi 1が3であり、これはスレッド1とスレッド2でそれぞれのi 1の値が変化しています。また、この変更はまだmain memoryや他のスレッドに伝えられていないときに発生します。
geti 2()が得られたのは、main memoryのi 2値です。一つの変数宣言はvolatileであり、この変数はいつでも他のスレッドによって修正されることを意味していますので、cacheをスレッドmemoryに登録することはできません。言い換えれば、一つの変数はvolatileで修飾された後、すべてのスレッドで同期されなければなりません。任意のスレッドでその値が変更され、他のスレッドは直ちに同じ値が得られます。だから、volatile修飾の変数のアクセスは、一般的な変数よりも多くのリソースを消費します。
geti 3()方法はsynchronizedによって修正され、一つの方法または一つのローンをsynchronizedで修飾する場合、同じ時間に最大で一つのスレッドだけがこのコードを実行することを保証することができます。volatileキーワードがスレッド間データ同期を実現した以上、synchronizedは何をするべきですか?二つの同時スレッドが同じオブジェクトobjectにアクセスする時、このsynchronized(this)は同期してローンを借りれば、一つの時間で一つのスレッドしか実行できません。もう一つのスレッドは、現在のスレッドがこのコードブロックを実行するのを待つ必要があります。しかし、スレッドがobjectのsynchronized同期コードブロックにアクセスすると、他のスレッドはこのObjectの非synchronized同期コードブロックにまだアクセスすることができる。特に、スレッドがobjectのsynchronized同期コードブロックにアクセスすると、他のスレッドがobjectの中の他のすべてのsynchronized(this)同期コードブロックに対するアクセスが遮断される。スレッドがobjectのsynchronized同期コードブロックにアクセスすると、このObjectのオブジェクトロックが得られ、その結果、他のスレッドがこのオブジェクトに対してすべての同期コード部分へのアクセスが一時的にブロックされる。
違いをまとめてみます。
一、volatileは変数修飾子であり、synchronizedはコードまたは方法の一部に作用します。
Volatileはスレッドメモリとメインメモリの間にある変数の値を同期させるだけです。synchronizedは、あるモニタをロックし、ロックして、すべての変数の値を同期させます。明らかにsynchronizedはvolatileよりも多くの資源を消費している。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。