「ブール値で同期しない」必要がある理由がわかりません。
常に定数オブジェクトインスタンスsynchronize
を使用する必要があります。割り当てているオブジェクトで同期した場合(つまり、オブジェクトを新しいオブジェクトに変更した場合)、それは一定ではなく、さまざまなスレッドがさまざまなオブジェクトインスタンスで同期します。それらは異なるオブジェクトインスタンスで同期しているため、複数のスレッドが同時に保護されたブロックに入り、競合状態が発生します。これは、、などで同期する場合と同じ答えです。Long
Integer
// this is not final so it might reference different objects
Boolean isOn = true;
...
synchronized (isOn) {
if (isOn) {
// this changes the synchronized object isOn to another object
// so another thread can then enter the synchronized with this thread
isOn = false;
さらに悪いことに、Boolean
オートボクシング()によって作成されたものは、すべてのオブジェクトのシングルトンである(または)isOn = true
と同じオブジェクトです。ロックオブジェクトは、それが使用されているクラスに対してローカルである必要があります。そうでない場合、他のクラスが同じ間違いを犯している場合に他のクラスがロックする可能性があるのと同じシングルトンオブジェクトをロックします。Boolean.TRUE
.FALSE
ClassLoader
ブール値をロックする必要がある場合の適切なパターンは、private final
ロックオブジェクトを定義することです。
private final Object lock = new Object();
...
synchronized (lock) {
...
または、オブジェクトの使用も検討する必要AtomicBoolean
があります。つまり、オブジェクトをまったく使用する必要がない場合がありますsynchronize
。
private final AtomicBoolean isOn = new AtomicBoolean(false);
...
// if it is set to false then set it to true, no synchronization needed
if (isOn.compareAndSet(false, true)) {
statusMessage = "I'm now on";
} else {
// it was already on
statusMessage = "I'm already on";
}
あなたの場合、スレッドでオン/オフを切り替える必要があるように見えるのでsynchronize
、オブジェクトをオンにしlock
てブール値を設定し、競合状態のテスト/設定を回避する必要があります。
synchronized (lock) {
if (isOn) {
isOn = false;
statusMessage = "I'm off";
// Do everything else to turn the thing off
} else {
isOn = true;
statusMessage = "I'm on";
// Do everything else to turn the thing on
}
}
最後に、他のスレッドからアクセスされることが予想される場合は、取得中にもアクセスしない限りstatusMessage
、としてマークを付ける必要があります。volatile
synchronize