Как синхронизировать статическую переменную между потоками, выполняющими разные экземпляры класса в Java? - PullRequest
116 голосов
/ 22 января 2010

Я знаю, что использование ключевого слова synchronize до того, как метод принесет синхронизацию этому объекту. То есть 2 потока, выполняющие один и тот же экземпляр объекта, будут синхронизированы.

Однако, поскольку синхронизация находится на уровне объекта, 2 потока, выполняющие разные экземпляры объекта, не будут синхронизированы. Если у нас есть статическая переменная в классе Java, которая вызывается методом, мы хотели бы, чтобы она синхронизировалась между экземплярами класса. Два экземпляра работают в 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?

Ответы [ 4 ]

186 голосов
/ 22 января 2010

Существует несколько способов синхронизации доступа к статической переменной.

  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 является лучшим во многих случаях, потому что объект блокировки не открыт вне вашего класса.

62 голосов
/ 22 января 2010

Если вы просто делитесь счетчиком, рассмотрите возможность использования AtomicInteger или другого подходящего класса из пакета java.util.concurrent.atomic:

public class Test {

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

    public void foo() {  
        count.incrementAndGet();
    }  
}
4 голосов
/ 22 января 2010

Да, это правда.

Если вы создаете два экземпляра вашего класса

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

Затем t1.foo и t2.foo синхронизируются на одном и том же статическом объекте и, следовательно, блокируют друг друга.

0 голосов
/ 12 января 2013

Вы можете синхронизировать свой код по классу. Это было бы проще всего.

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

Надеюсь, вы найдете этот ответ полезным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...