Class Future
{
private volatile boolean ready;
private Object data;
public Object get()
{
if(!ready) return null;
return data;
}
public synchronized void setOnce(Object o)
{
if(ready) throw...;
data = o;
ready = true;
}
}
「スレッドがデータを読み取る場合、データの可視性を保証する書き込みから読み取りまでのハプニング ビフォア エッジがあります」
私は私の学習から知っています:
- volatile は、すべての読み取り/書き込みが、キャッシュまたはレジスタだけではなく、メモリ内にあることを保証します。
- volatile は並べ替えを保証します。つまり、setOnce() メソッドで data = o をスケジュールできるのは、if(ready) throw... の後、ready = true; の前だけです。これにより、get() で ready = true の場合、データは o でなければならないことが保証されます。
私の混乱は
スレッド 1 が setOnce() にあるときに、data = o; の後に到達する可能性はありますか? 準備ができている前に = true; 同時に、スレッド 2 が get() に実行され、read ready が false になり、null が返されます。そして、thead 1 は ready = true を続けます。このシナリオでは、スレッド 1 でデータに新しい値が割り当てられていても、スレッド 2 は新しい「データ」を認識しませんでした。
get() は同期されていません。つまり、同期ロックは setOnce() を保護できません。これは、スレッド 1 が get() を呼び出して、変数 Ready のデータにアクセスするためにロックを取得する必要がないためです。そのため、スレッドはデータの最新の値を確認できるとは限りません。これにより、ロックは同期されたブロック間の可視性のみを保証することを意味します。1 つのスレッドが同期ブロック setOnce() を実行していても、別のスレッドは引き続き get() に入り、ブロックせずに Ready とデータにアクセスでき、これらの変数の古い値が表示される場合があります。
get() で、ready = true の場合、データは o でなければなりませんか? このスレッドは、データの可視性が保証されているということですか? データは揮発性でも get() 同期でもないと思います。このスレッドはキャッシュ内の古い値を参照できますか?
ありがとう!