разница между синхронизацией статического метода и нестатического метода - PullRequest
27 голосов
/ 16 июня 2011

В чем разница между синхронизацией статического метода и нестатического метода в Java? Кто-нибудь может объяснить, пожалуйста, с примером. Также есть ли разница в синхронизации метода и синхронизации блока кода?

Ответы [ 7 ]

74 голосов
/ 16 июня 2011

Я попытаюсь добавить пример, чтобы прояснить ситуацию.

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

Object a = new Object();
Object b = new Object();
...
synchronized(a){
    doStuff();
}
...
synchronized(b){
    doSomeStuff();
}
...
synchronized(a){
    doOtherStuff();
}

В приведенном выше примере поток, выполняющий doOtherStuff(), заблокирует другой поток от входа в блок кода, защищающий doStuff(). Однако поток может без проблем войти в блок около doSomeStuff(), поскольку он синхронизируется на Object b, а не Object a.

Когда вы используете синхронизированный модификатор в методе экземпляра (нестатический метод), это очень похоже на наличие синхронизированного блока с «this» в качестве аргумента. Таким образом, в следующем примере methodA() и methodB() будут действовать одинаково:

public synchronized void methodA() {
  doStuff();
}
...
public void methodB() {
    synchronized(this) {
        doStuff();
    }
}

Обратите внимание, что если у вас есть methodC() в этом классе, который не синхронизирован и не имеет синхронизированного блока, ничто не помешает потоку войти в этот метод, и неосторожное программирование может позволить этому потоку получить доступ к небезопасному коду в объект. * * тысяча двадцать-один

Если у вас есть статический метод с модификатором synchronized, это практически то же самое, что иметь синхронизированный блок с ClassName.class в качестве аргумента (если у вас есть объект этого класса, ClassName cn = new ClassName();, вы можете получить к нему доступ объект с Class c = cn.getClass();)

class ClassName {
  public void static synchronized staticMethodA() {
    doStaticStuff();
  }
  public static void staticMethodB() {
    synchronized(ClassName.class) {
      doStaticStuff();
    }
  }
  public void nonStaticMethodC() {
    synchronized(this.getClass()) {
      doStuff();
    }
  }
  public static void unSafeStaticMethodD() {
   doStaticStuff();
  }
}

Итак, в приведенном выше примере staticMethodA() и staticMethodB() действуют одинаково. Выполняющему потоку также будет заблокирован доступ к блоку кода в nonStaticMethodC(), поскольку он синхронизируется с тем же объектом.

Однако важно знать, что ничто не помешает исполняющему потоку получить доступ к unSafeStaticMethodD(). Даже если мы говорим, что статический метод «синхронизируется с объектом Class», это не означает, что он синхронизирует все обращения к методам в этом классе. Это просто означает, что он использует объект Class для синхронизации. Небезопасный доступ все еще возможен.

19 голосов
/ 16 июня 2011

Короче говоря, если вы синхронизируете по статическому методу, вы будете синхронизироваться по классу (объекту), а не по экземпляру (объекту). Это означает, что при выполнении статического метода весь класс блокируется. Поэтому другие статические синхронизированные методы также блокируются.

4 голосов
/ 16 июня 2011

Синхронизация в Java в основном представляет собой реализацию мониторов . При синхронизации нестатического метода монитор принадлежит экземпляру. При синхронизации по статическому методу монитор относится к классу. Синхронизация блока кода - та же идея, но монитор принадлежит указанному объекту. Если вам это удастся, синхронизированные блоки предпочтительнее, поскольку они минимизируют время, которое каждый поток проводит в критической секции

3 голосов
/ 16 июня 2011

Практически нет разницы между синхронизацией блока и синхронизацией метода.В основном:

void synchronized m() {...}

совпадает с

void m() { synchronized(this) {...} }

Для сравнения метод статической синхронизации такой же, как:

static void m() { synchronized(MyClass.class) {...} }
0 голосов
/ 02 сентября 2018

Из Javadoc https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

когда вызывается статический синхронизированный метод, так как статический метод связан с классом, а не объектом. В этом случае поток получает внутреннюю блокировку для объекта Class, связанного с классом. Таким образом, доступ к статическим полям класса контролируется блокировкой, отличной от блокировки для любого экземпляра класса.

public static synchronized void getInstance(){}

Когда мы получаем блокировку для любого класса, мы фактически получаем блокировку для экземпляра класса "Class", который является единым для всех экземпляров класса.

public synchronized void getInstance(){}

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

0 голосов
/ 23 декабря 2015

Поток Java получает блокировку уровня объекта, когда входит в экземпляр синхронизированный метод Java и получает блокировка на уровне класса при входе в статический синхронизированный метод java . Используя синхронизированный блок , вы можете заблокировать только критическую часть кода и избежать блокировки всего метода, который может снизить производительность.

0 голосов
/ 13 мая 2013

Чувак, просто намек.Не относится к вашему вопросу:

Если какой-либо из методов do * Stuff () делает либо

this.a= /*yet another*/ new Object();

, либо

this.b= /*yet another*/ new Object();

, тогда вы ввернуты.Потому что блокировка находится внутри значения, а не внутри ссылки.См. Синхронизированные ссылки Java

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