スレッド セーフの主要な要素は、相互排除だけではありません。オブジェクトの状態のアトミックな更新を完了することは十分に可能です。つまり、不変条件をそのままにしてオブジェクトを有効な状態のままにする状態遷移を実行できますが、その参照がまだ信頼できない、または不完全に公開されている場合は、オブジェクトを脆弱なままにしておくことができます。デバッグされたクライアント。
あなたが投稿した例では:
public synchronized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
WMが指摘したように、コードはスレッドセーフです。x
しかし、それ自体と、他のコードによってまだ参照が保持されている可能性がある場所については保証されていません。そのような参照が存在した場合、別のスレッドがリスト内の対応する要素を変更する可能性があり、リスト内のオブジェクトの不変条件を保護する努力が無効になります。
信頼できない、または知らないクライアント コードからこのリストに要素を受け入れる場合は、x の防御コピーを作成し、それをリストに追加することをお勧めします。同様に、リストから他のクライアント コードにオブジェクトを返す場合は、防御的なコピーを作成して返すことで、リストがスレッド セーフのままであることを保証できます。
さらに、リストはクラスに完全にカプセル化する必要があります。パブリックにすることで、クライアント コードはどこからでも要素に自由にアクセスでき、リスト内のオブジェクトの状態を保護できなくなります。