web-dev-qa-db-ja.com

Javaのクラスの異なるインスタンスを実行しているスレッド間で静的変数を同期する方法は?

メソッドがそのオブジェクトに同期をもたらす前にsynchronizeキーワードを使用することを知っています。つまり、オブジェクトの同じインスタンスを実行している2つのスレッドが同期されます。

ただし、同期はオブジェクトレベルで行われるため、オブジェクトの異なるインスタンスを実行する2つのスレッドは同期されません。メソッドによって呼び出されるJavaクラスに静的変数がある場合、そのクラスのインスタンス間で同期されるようにします。 2つのインスタンスは2つの異なるスレッドで実行されています。

次の方法で同期を実現できますか?

public class Test  
{  
   private static int count = 0;  
   private static final Object lock= new Object();    
   public synchronized void foo() 
  {  
      synchronized(lock)
     {  
         count++;  
     }  
  }  
}

静的なオブジェクトlockを定義し、そのロックにキーワードsynchronizedを使用しているため、クラスcountのインスタンス間で静的変数Testが同期されるのは本当ですか?

118
Anonymous

静的変数へのアクセスを同期するには、いくつかの方法があります。

  1. 同期静的メソッドを使用します。これは、クラスオブジェクトで同期します。

    public class Test {
        private static int count = 0;
    
        public static synchronized void incrementCount() {
            count++;
        }
    } 
    
  2. クラスオブジェクトで明示的に同期します。

    public class Test {
        private static int count = 0;
    
        public void incrementCount() {
            synchronized (Test.class) {
                count++;
            }
        }
    } 
    
  3. 他の静的オブジェクトで同期します。

    public class Test {
        private static int count = 0;
        private static final Object countLock = new Object();
    
        public void incrementCount() {
            synchronized (countLock) {
                count++;
            }
        }
    } 
    

方法3は、ロックオブジェクトがクラスの外部に公開されないため、多くの場合に最適です。

188
Darron

単にカウンターを共有する場合は、 AtomicInteger またはJava.util.concurrent.atomicパッケージの別の適切なクラスを使用することを検討してください。

public class Test {

    private final static AtomicInteger count = new AtomicInteger(0); 

    public void foo() {  
        count.incrementAndGet();
    }  
}
63
Kevin

はい、そうです。

クラスの2つのインスタンスを作成する場合

Test t1 = new Test();
Test t2 = new Test();

次に、t1.fooとt2.fooは両方とも同じ静的オブジェクトで同期するため、互いにブロックします。

4
richs