競合状態は、2 つのスレッドが同じリソースに同時にアクセスし、1 つ以上のスレッドがこのリソースに書き込む場合にのみ発生します。複数のスレッドが同じリソースを読み取る場合、競合状態は発生しません。
共有オブジェクトを不変にし、どのスレッドによっても更新されないようにすることで、スレッド間で共有されるオブジェクトがスレッドセーフであることを確認できます。以下に例を示します。
public class ImmutableValue{ private int value = 0; public ImmutableValue(int value){ this.value = value; } public int getValue(){ return this.value; } }
ImmutableValue インスタンスの値がこのコンストラクターにどのように渡されるかに注目してください。ここでは決まった方法がないことにも注意してください。このインスタンスが作成されると、その値を変更することはできません。それは不変です。ただし、get メソッドを使用して読み取ることはできます。
このインスタンスに対して操作を実行する必要がある場合は、操作結果の値を含む新しいインスタンスを返すことができます。以下に例を示します。
public class ImmutableValue{ private int value = 0; public ImmutableValue(int value){ this.value = value; } public int getValue(){ return this.value; } <strong>public ImmutableValue add(int valueToAdd){ return new ImmutableValue(this.value + valueToAdd); }</strong> }
add メソッドは、それ自体に値を追加するのではなく、追加操作の結果を含む新しいインスタンスを返すことに注意してください。
この参照はスレッドセーフではありません
オブジェクトが不変でスレッドセーフであっても、このオブジェクトへの参照はスレッドセーフではない可能性があることに留意することが重要です。この例を見てください:
public class Calculator{ private ImmutableValue currentValue = null; public ImmutableValue getValue(){ return currentValue; } public void setValue(ImmutableValue newValue){ this.currentValue = newValue; } public void add(int newValue){ this.currentValue = this.currentValue.add(newValue); } }
この Calculator クラスは、上記のオブジェクトへの参照を保持します。 setValue メソッドと add メソッドを通じてその参照が変更される可能性があることに注意してください。したがって、このクラスが内部で不変オブジェクトを使用している場合でも、それ自体は不変ではないため、スレッドセーフではありません。言い換えれば、この ImmutableValue クラスはスレッドセーフですが、その使用法はスレッドセーフではありません。これは、不変性によってスレッドの安全性を実現しようとするときに留意すべきことです。
Calculator クラスをスレッドセーフにするには、getValue()、setValue()、および add() メソッドで synchronized キーワードを使用する必要があります。それでうまくいきます。
上記は Java スレッドの安全性と不変性の内容です。さらに関連する内容については、PHP 中国語 Web サイト (www.php.cn) に注目してください。