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

148

Документация Java гласит:

Невозможно чередовать два вызова синхронизированных методов для одного и того же объекта.

Что это значит для статического метода? Поскольку статический метод не имеет связанного объекта, будет ли синхронизированное ключевое слово блокироваться на классе, а не на объекте?

JBU
источник

Ответы:

129

Поскольку статический метод не имеет связанного объекта, будет ли синхронизированное ключевое слово блокироваться на классе, а не на объекте?

Да. :)

OscarRyz
источник
81
Пожалуйста, ответьте «Разработать», чтобы все могли понять
Мадху
6
@Madhu. Это означает, что если у вас есть 2 или более синхронизированных метода в одном классе, оба не могут выполняться одновременно, даже если есть несколько экземпляров этого класса. Блокировка по сути такая же, как и блокировка в Object.class для каждого синхронизированного метода.
Стивен
Этот ответ неверен - thisэто блокировка, полученная при использовании методов экземпляра, пожалуйста, исправьте это, Оскар.
Vemv
1
@vemv Вопрос касается методов класса, а не методов экземпляра.
OscarRyz
23
@vemv Ну да, чтобы понять ответ, сначала прочитайте вопрос.
OscarRyz
199

Просто чтобы добавить немного подробностей к ответу Оскара (приятно лаконично!), Соответствующий раздел в спецификации языка Java - 8.4.3.6, «синхронизированные методы» :

Синхронизированный метод получает монитор ( §17.1 ), прежде чем он выполняется. Для метода класса (статического) используется монитор, связанный с объектом Class для класса метода. Для метода экземпляра используется монитор, связанный с этим (объект, для которого был вызван метод).

Коуэн
источник
17
Полезно, я искал эту цитату +1
OscarRyz
80

Вы должны быть осторожны (некоторые ловушки обычно попадают в эту ловушку): нет никакой связи между синхронизированными статическими методами и синхронизированными нестатическими методами, то есть:

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

Основной:

A a = new A();

Тема 1:

A.f();

Тема 2:

a.g();

f () и g () не синхронизированы друг с другом и, таким образом, могут выполняться полностью одновременно.

jfpoilpret
источник
18
но что если g () изменяет некоторую статическую переменную, которую читает f (). Как мы можем сделать эту нить безопасной? Тогда мы явно получим блокировку класса?
Baskin
22
Да, ваш нестатический метод должен явно синхронизироваться с самим классом (т synchronized (MyClass.class) {...}.
Е.
@jfpoilpret "synchronized (MyClass.class) {...}" эквивалентно тому, чтобы этот метод был статически синхронизирован, верно?
сумасшедший
15

Если вы не реализуете g () следующим образом:

g() {
    synchronized(getClass()) {
        ...
    }
}

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

примерочных всеобъемлющая наконец
источник
63
Обратите внимание, что здесь могут быть некоторые очень тонкие и неприятные ошибки. Помните, getClass()возвращает тип времени выполнения ; если вы создадите подкласс класса, то родительский класс и дочерний класс будут синхронизироваться при разных блокировках. synchronized(MyClass.class)это путь, если вам нужно убедиться, что все экземпляры используют одну и ту же блокировку.
Коуэн
4

Взгляните на страницу документации оракула о внутренних замках и синхронизации

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

Равиндра Бабу
источник
2

Статический метод также имеет связанный объект. Он принадлежит файлу Class.class в наборе инструментов JDK. Когда файл .class загружается в оперативную память, Class.class создает его экземпляр, называемый объектом шаблона.

Например: - когда вы пытаетесь создать объект из существующего класса клиента, как

Customer c = new Customer();

Загрузка Customer.class в оперативную память. В этот момент Class.class в JDK toolkit создает объект с именем Template и загружает этот Customer.class в этот объект шаблона. Статические члены этого Customer.class становятся атрибутами и методами в этом объекте шаблона.

Таким образом, статический метод или атрибут также имеет объект

Пахансит Ганатилаке
источник
2

Приведенные ниже примеры дают больше ясности между блокировкой классов и объектов, надеюсь, что приведенный ниже пример поможет и другим :)

Например, у нас есть следующие методы: один получить класс, а другой получить объект блокировки:

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

Итак, теперь у нас могут быть следующие сценарии:

  1. Когда потоки, использующие один и тот же объект, пытаются получить доступ к методу objLock OR в staticLock одно и то же время (т.е. оба потока пытаются получить доступ к одному и тому же методу)

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  2. Когда потоки, использующие один и тот же объект, пытаются получить доступ staticLockи objLockметоды в одно и то же время (пытается получить доступ к различным методам)

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
  3. Когда потоки, использующие другой объект, пытаются получить доступ к staticLockметоду

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  4. Когда потоки, использующие другой объект, пытаются получить доступ к objLockметоду

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
Ravi
источник
0

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

Pragya
источник