JAVA では、synchronized ステートメントを使用してマルチスレッドの同時実行を実現できます。 JVM は、同期されたコード ブロックを使用して、同時に 1 つのスレッドだけが特定のオブジェクトのロックを保持できるようにします。ロック メカニズムにより、複数のスレッドが重要なリソースに安全にアクセスできるようになります。
同期コードは次のように記述されます。
コード 1:
Object obj = new Object(); ... synchronized(obj) { //TODO: 重要なリソースにアクセスする} JAVA のマルチスレッドは常にトラップでいっぱいです。同期オブジェクトとして Boolean を使用すると、次の 2 つの状況が発生する可能性があります。
1. 1 つのオブジェクトがロックされているように見えますが、実際には別のオブジェクトが同期されています。
コード 2:
private volatile Boolean isTrue = false; publich void aMethod() { ... synchronized(isTrue) { isTrue = !isTrue; //TODO: 重要なリソースにアクセスします isTrue = !isTrue;一見すると、上記のコードには何も問題はありません。 synchronized(isTrue) を使用しているため、重要なリソースに同時にアクセスできるのは 1 つのスレッドだけですが、実際はそうではありません。 2 つの定数 false と true が 2 つの異なるオブジェクトに対応するためです。 isTrue が変化すると、異なるスレッドが異なるオブジェクトを同期する可能性があります。 JAVA の自動ボックス化では、false が Boolean.FALSE に、true が Boolean.TRUE に変更されます (これは、false が Boolean.FALSE に変更された場合でも、結果は同じになることを示しています)。上記のいずれかの状況に対するテスト コードを次のように記述します。
コード 3:
public class BooleanTest { private volatile Boolean isTrue = Boolean.FALSE; //ここでは false と同じです public void aMethod() { for(int i=0;i<10;i++) { Thread t = new Thread() { public void run() { synchronized(isTrue) { isTrue = !isTrue; System.out.println(Thread.currentThread().getName() + " - isTrue= + isTrue); try{ Double ran = 1000 * Math.random(); Thread.sleep(ran.intValue()); }catch(InterruptedException e) {} if(!isTrue) System.out.println( Thread.currentThread().getName() + " - いいえ!"); isTrue = !isTrue; t.start(); } } public static void main(String... args) { BooleanTest bt = new BooleanTest(); } }上記のコードを実行すると、「-Oh, No!」というメッセージが時々表示されます。これは、異なるスレッドが同期されたコード ブロックに同時に入っていることを示しています。
2. 異なるオブジェクトが同期しているように見えますが、実際には 1 つのオブジェクトです。
場合によっては、複数のオブジェクトを同期する必要がある場合があります。同期オブジェクトとして Boolean を使用すると、関係のない 2 つの同期ブロックが同じオブジェクト ロックを使用する可能性があります。例は次のとおりです。
コード 4:
private volatile Boolean aBoolean = Boolean.FALSE; private volatile Boolean anotherBoolean = false; public void aMethod() { ... synchronized(aBoolean) { //TODO: 重要なリソース 1 にアクセスします } ... } public void anotherMethod() { . .. synchronized(anotherBoolean) { //TODO: 重要なリソース 2 にアクセスします } ... }当初、aMethod と anotherMethod が 2 セットの無関係なスレッドによって呼び出されると仮定します。ただし、Boolean.FALSE と false は同じオブジェクトを指しているため、クリティカル リソース 2 へのアクセスはクリティカル リソース 1 によってブロックされる可能性があります (逆も同様)。
上記の 2 つの状況は、同期ブロックを使用する場合、ブール値オブジェクトを同期オブジェクトとして使用しないようにしてください。そうしないと、予期しない問題が発生したり、将来のコード変更でトラップが発生したりする可能性があることを示しています。
このことから、定数の同期には危険が伴うこともわかります。ブール値を同期する必要がある場合は、new 演算子を使用してブール値オブジェクトを作成する必要があります。