Zsynchronizowane metody statyczne Java: blokowanie obiektu lub klasy

148

Dokumentacja Java mówi:

Nie ma możliwości przeplotu dwóch wywołań metod zsynchronizowanych na tym samym obiekcie.

Co to oznacza dla metody statycznej? Ponieważ metoda statyczna nie ma skojarzonego obiektu, czy synchronizowane słowo kluczowe będzie blokować klasę zamiast obiektu?

jbu
źródło

Odpowiedzi:

129

Ponieważ metoda statyczna nie ma skojarzonego obiektu, czy synchronizowane słowo kluczowe będzie blokować klasę zamiast obiektu?

Tak. :)

OscarRyz
źródło
81
Odpowiedz Rozwiń, aby każdy mógł zrozumieć.
Madhu
6
@Madhu. Oznacza to, że jeśli masz 2 lub więcej zsynchronizowanych metod w tej samej klasie, obie nie mogą być wykonywane w tym samym czasie, nawet jeśli istnieje wiele instancji tej klasy. Blokowanie jest zasadniczo takie samo, jak blokowanie w Object.class dla każdej zsynchronizowanej metody.
Steven
Ta odpowiedź jest błędna - thisczy blokada uzyskana w metodach instancji - napraw ją Oscar.
vemv
1
@vemv Pytanie dotyczy metod klasowych, a nie instancji.
OscarRyz
23
@vemv Cóż, tak, aby zrozumieć odpowiedź, musisz najpierw przeczytać pytanie.
OscarRyz
199

Aby dodać trochę szczegółów do (przyjemnie zwięzłej!) Odpowiedzi Oscara, odpowiednia sekcja specyfikacji języka Java to 8.4.3.6, `` Metody synchronizowane '' :

Zsynchronizowana metoda pozyskuje monitor ( §17.1 ) przed wykonaniem. W przypadku metody klasowej (statycznej) używany jest monitor skojarzony z obiektem Class dla klasy metody. W przypadku metody instancji używany jest monitor z nią powiązany (obiekt, dla którego metoda została wywołana).

Cowan
źródło
17
Przydatne, szukałem tego cytatu +1
OscarRyz
80

Jedną kwestią, na którą trzeba uważać (kilku programistów zazwyczaj wpada w tę pułapkę) jest to, że nie ma połączenia między zsynchronizowanymi metodami statycznymi a zsynchronizowanymi metodami niestatycznymi, tj .:

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

Główny:

A a = new A();

Wątek 1:

A.f();

Wątek 2:

a.g();

f () i g () nie są zsynchronizowane ze sobą i dlatego mogą być wykonywane całkowicie współbieżnie.

jfpoilpret
źródło
18
ale co jeśli g () mutuje jakąś zmienną statyczną, którą czyta f (). Jak zabezpieczymy ten wątek? Czy wtedy jawnie uzyskujemy blokadę klasy?
baskin
22
Tak, Twoja niestatyczna metoda musi jawnie synchronizować się z samą klasą (tj synchronized (MyClass.class) {...}.
jfpoilpret
@jfpoilpret "synchronized (MyClass.class) {...}" jest równoważne uczynieniu tej metody statyczną synchronizacją, prawda?
crazymind
15

O ile nie zaimplementujesz g () w następujący sposób:

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

Uważam, że ten wzorzec jest przydatny również wtedy, gdy chcę zaimplementować wzajemne wykluczanie między różnymi instancjami obiektu (co jest potrzebne na przykład przy dostępie do zasobu zewnętrznego).

wreszcie spróbuj złapać
źródło
63
Zauważ, że w rzeczywistości może istnieć tutaj szansa na bardzo subtelne i paskudne błędy. Remember getClass()zwraca typ środowiska uruchomieniowego ; jeśli podklasujesz klasę, to klasa nadrzędna i klasa potomna będą synchronizowane na różnych blokadach. synchronized(MyClass.class)jest dobrym rozwiązaniem, jeśli chcesz upewnić się, że wszystkie instancje używają tej samej blokady.
Cowan
4

Zajrzyj na stronę dokumentacji oracle na temat Intrinsic Locks and Synchronization

Możesz się zastanawiać, co się dzieje, gdy wywoływana jest statyczna metoda zsynchronizowana, ponieważ metoda statyczna jest skojarzona z klasą, a nie z obiektem. W takim przypadku wątek uzyskuje wewnętrzną blokadę dla obiektu Class skojarzonego z klasą . W ten sposób dostęp do pól statycznych klasy jest kontrolowany przez blokadę, która różni się od blokady dla dowolnej instancji klasy .

Ravindra babu
źródło
2

Metoda statyczna ma również powiązany obiekt. Należy do pliku Class.class w zestawie narzędzi JDK. Gdy plik .class ładuje się do pamięci RAM, klasa Class.class tworzy jego instancję o nazwie obiekt szablonu.

Np .: - gdy próbujesz stworzyć obiekt z istniejącej klasy klienta np

Customer c = new Customer();

Klasa Customer.class ładuje się do pamięci RAM. W tym momencie Class.class w zestawie narzędzi JDK tworzy obiekt o nazwie obiekt szablonu i ładuje tę klasę Customer.class do tego obiektu szablonu. Statyczne elementy składowe klasy Customer.class stają się atrybutami i metodami w tym obiekcie szablonu.

Zatem statyczna metoda lub atrybut również ma obiekt

Pahansith Gunathilake
źródło
2

Poniższe przykłady dają większą jasność między blokadą klasy i obiektu, mam nadzieję, że poniższy przykład pomoże również innym :)

Na przykład mamy poniżej metody, z których jedna uzyskuje klasę, a druga uzyskuje blokadę obiektu:

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);
        }
    }
}

Więc teraz możemy mieć następujące scenariusze:

  1. Gdy wątki używające tego samego obiektu próbują uzyskać dostęp do metody objLock LUB w staticLock tym samym czasie (tj. Oba wątki próbują uzyskać dostęp do tej samej metody)

    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. Gdy wątki używające tego samego obiektu próbują uzyskać dostęp staticLocki objLockmetody w tym samym czasie (próbują uzyskać dostęp do różnych metod)

    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. Gdy wątki używające innego obiektu Object próbują uzyskać dostęp do staticLockmetody

    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. Gdy wątki używające innego obiektu Object próbują uzyskać dostęp do objLockmetody

    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
źródło
0

Dla tych, którzy nie są zaznajomieni ze statyczną metodą synchronizowaną zablokowaną na obiekcie klasy, np. Dla klasy string, jej String.class, podczas gdy instancja synchronizowana metoda blokuje bieżącą instancję Object oznaczoną słowem kluczowym „this” w Javie. Ponieważ oba te obiekty są różne, mają różne blokady, więc gdy jeden wątek wykonuje statyczną metodę zsynchronizowaną, inny wątek w java nie musi czekać na powrót tego wątku, zamiast tego uzyska oddzielną blokadę oznaczoną bajtem. Class i wejdzie do statyczna metoda synchroniczna.

Pragya
źródło