Синхронизированный метод Java соединяет объект или метод?

Если у меня есть 2 синхронизированных метода в том же классе, но каждый получающие доступ различные переменные, действительно ли 2 потока могут получить доступ к тем 2 методам одновременно? Блокировка происходит на объекте, или это становится столь же конкретным как переменные в синхронизированном методе?

Пример:

class X {

    private int a;
    private int b;

    public synchronized void addA(){
        a++;
    }

    public synchronized void addB(){
        b++;
    }

}

Могут 2 потока получать доступ к тому же экземпляру выполнения класса X x.addA() и x.addB() одновременно?

175
задан informatik01 12 August 2013 в 01:42
поделиться

4 ответа

Если вы объявляете метод как синхронизированный (как вы это делаете, набирая public synchronized void addA () ), вы синхронизируете весь объект , поэтому два потока, обращающиеся к другой переменной из этого же объекта, в любом случае будут блокировать друг друга.

Если вы хотите синхронизировать только одну переменную за раз, чтобы два потока не блокировали друг друга при доступе к разным переменным, вы должны синхронизировать их отдельно в блоках synchronized () . Если бы a и b были ссылками на объекты, вы бы использовали:

public void addA() {
    synchronized( a ) {
        a++;
    }
}

public void addB() {
    synchronized( b ) {
        b++;
    }
}

Но поскольку они примитивны, вы не можете этого сделать.

Я бы посоветовал вам вместо этого использовать AtomicInteger :

import java.util.concurrent.atomic.AtomicInteger;

class X {

    AtomicInteger a;
    AtomicInteger b;

    public void addA(){
        a.incrementAndGet();
    }

    public void addB(){ 
        b.incrementAndGet();
    }
}
180
ответ дан 23 November 2019 в 20:27
поделиться

Синхронизация в объявлении метода является синтаксическим сахаром для этого:

 public void addA() {
     synchronized (this) {
          a++;
     }
  }

Для статического метода это синтаксический сахар для этого:

 ClassA {
     public static void addA() {
          synchronized(ClassA.class) {
              a++;
          }
 }

Я думаю, если бы разработчики Java знали тогда, что понимается сейчас о синхронизации, они не добавили бы синтаксический сахар, так как это чаще всего приводит к плохой реализации параллелизма.

66
ответ дан 23 November 2019 в 20:27
поделиться

Доступ к блокировке осуществляется на объекте, а не на методе. Какие переменные доступны в методе, не имеет значения.

Добавление «синхронизировано» к методу означает, что поток, выполняющий код, должен получить блокировку объекта перед продолжением. Добавление «статической синхронизации» означает, что поток, выполняющий код, должен получить блокировку объекта класса перед продолжением. В качестве альтернативы вы можете заключить код в такой блок:

public void addA() {
    synchronized(this) {
        a++;
    }
}

, чтобы вы могли указать объект, блокировка которого должна быть получена.

Если вы хотите избежать блокировки содержащего объекта, вы можете выбрать между:

14
ответ дан 23 November 2019 в 20:27
поделиться

Вы можете сделать что-то вроде следующего. В этом случае вы используете блокировку на a и b для синхронизации вместо блокировки на "this". Мы не можем использовать int, потому что примитивные значения не имеют блокировок, поэтому мы используем Integer.

class x{
   private Integer a;
   private Integer b;
   public void addA(){
      synchronized(a) {
         a++;
      }
   }
   public synchronized void addB(){
      synchronized(b) {
         b++;
      }
   }
}
3
ответ дан 23 November 2019 в 20:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: