volatile修飾子の概要
- 変数に付与する修飾子だよ。場合によってはsynchronizedの代わりに使える。
- 以下が利用例。
private static volatile int count = 0;
役割1: キャッシュ値からの読み取りを禁止する
- マルチスレッドが使われている場合、各スレッドがフィールドの値をキャッシュすることがある。このキャシュの対象外にする役割(パフォーマンス向上のために、各スレッドが変数のコピーを用意するため、メインメモリの値に変更があると、スレッド内の値と乖離が発生する可能性がある)
- volatileつけるとこの変数はメインメモリから読み込んでねというお願いができる。
役割2: コンパイル時の最適化の対象外にする
- Javaのコンパイル時には無駄な評価をなくすように最適化が行われる。
# 以下のようなコードは...
boolean flg = true;
while(flg){
System.out.println("hello!");
}
# 以下のように最適化される... → 別スレッドでflgをfalseに変更する前提だとループが終わらない!
if(flg){
while(true){
System.out.println("hello!");
}
}
- volatileを付与することで上記のような最適化をおこなわないようにしてね、というお願いができる。
synchronizedとの違いは?
- synchronizedの方が高機能(volatileはsynchronizedの簡易版的な感じ)
- volatileは上記の役割を持つが、スレッドセーフというわけではない。
- volatileはスレッドとメインメモリ間の変数を同期する(=キャッシュせずに値をメインメモリから読みとりますよ)役割であるが、synchronizedはそれに加え、排他制御を行いますよという役割も持つ。
- volatileが排他制御に使えますよ、っていうのは間違い。
参考文献
[Difference Between Volatile and Synchronized Keywords in Java]
https://dzone.com/articles/difference-between-volatile-and-synchronized-keywo