Синхронізовані статичні методи Java: блокування об'єкта чи класу


148

Документація Java говорить:

Неможливо переплутати два виклики синхронізованих методів на одному об’єкті.

Що це означає для статичного методу? Оскільки статичний метод не має асоційованого об’єкта, чи заблокує синхронізоване ключове слово в класі замість об'єкта?

Відповіді:


129

Оскільки статичний метод не має асоційованого об’єкта, чи заблокує синхронізоване ключове слово на класі замість об'єкта?

Так. :)


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 () не синхронізуються один з одним і, таким чином, можуть виконуватися повністю одночасно.


18
але що робити, якщо g () мутує деяку статичну змінну, яку читає f (). Як зробити цю нитку безпечною? Чи явно ми тоді придбаємо замок для класу?
баскін

22
Так, ваш нестатичний метод повинен явно синхронізуватися на самому класі (тобто synchronized (MyClass.class) {...}.
jfpoilpret

@jfpoilpret "синхронізований (MyClass.class) {...}" еквівалентно зробити цей метод статичним синхронізованим, правда?
crazymind

15

Якщо ви не реалізуєте g () наступним чином:

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

Я вважаю цю закономірність корисною і тоді, коли хочу здійснити взаємне виключення між різними екземплярами об'єкта (що потрібно, наприклад, для доступу до зовнішнього ресурсу).


63
Зауважте, що насправді тут може бути ймовірність виникнення дуже тонких і неприємних помилок. Пам'ятайте, getClass()повертає тип виконання ; якщо ви підкласируете клас, то батьківський клас і дочірній клас синхронізуються на різних блоках. synchronized(MyClass.class)це шлях, якщо вам потрібно переконатися, що всі екземпляри використовують один і той же замок.
Кован

4

Перегляньте сторінку документації Oracle на тему " Внутрішні замки та синхронізація"

Вам може бути цікаво, що відбувається, коли викликається статичний синхронізований метод, оскільки статичний метод асоціюється з класом, а не об'єктом. У цьому випадку потік набуває внутрішнього блокування об’єкта Class, пов'язаного з класом . Таким чином, доступ до статичних полів класу контролюється замком, який відрізняється від блокування для будь-якого примірника класу .


2

Статичний метод також має пов'язаний об'єкт. Він належить файлу Class.class в наборі інструментів JDK. Коли файл .class завантажується в операційний пам'ять, Class.class створює екземпляр його під назвою об’єкт шаблону.

Наприклад: - коли ви намагаєтесь створити об'єкт із існуючого класу клієнтів, як

Customer c = new Customer();

Клас Customer.clas завантажується в оперативну пам'ять. У цей момент Class.class в наборі інструментів JDK створює об'єкт, який називається "Шаблон об'єкта", і завантажує його 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. Коли потоки, що використовують один і той же Object, намагаються одночасно отримати доступ до методу 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. Коли потоки, що використовують один і той же Object, намагаються отримати доступ 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

0

Для тих, хто не знайомий статичний синхронізований метод, заблокований на об'єкті класу, наприклад, для рядкового класу його String.class, а примірник синхронізованого методу блокується у поточному екземплярі Об'єкта, позначеному ключовим словом «це» у Java. Оскільки обидва ці об’єкти різні, вони мають різний замок, тому, коли одна нитка виконує статичний синхронізований метод, інший потік у Java не потребує очікування повернення цього потоку, а він придбає окремий замок, позначений байтом .class literal і ввійде в статичний синхронізований метод.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.