Java ile senkronize edilmiş statik yöntemler: nesne veya sınıfa kilitlenme


148

Java belgeleri şunu söylüyor:

Aynı nesne üzerinde iki senkronize yöntem çağrısının araya girmesi mümkün değildir.

Statik bir yöntem için bu ne anlama geliyor? Statik bir yöntemin ilişkili bir nesnesi olmadığından, senkronize edilmiş anahtar kelime nesne yerine sınıfta kilitlenir mi?

Yanıtlar:


129

Statik bir yöntemin ilişkili bir nesnesi olmadığından , senkronize edilmiş anahtar kelime nesne yerine sınıfta kilitlenir mi?

Evet. :)


81
Lütfen Ayrıntılı olarak yanıtlayın, böylece herkes anlayabilir.
Madhu

6
@Madhu. Bu, aynı sınıfta 2 veya daha fazla senkronize yönteminiz varsa, o sınıfın birden çok örneği olsa bile her ikisinin de aynı anda yürütülemeyeceği anlamına gelir. Kilitleme, her senkronize yöntem için Object.class üzerinde kilitleme ile temelde aynıdır.
Steven

Bu cevap yanlış - thisörnek yöntemlerinde edinilen kilit mi - lütfen düzeltin Oscar.
vemv

1
@vemv Soru, örnek yöntemlerle değil, sınıf yöntemleriyle ilgilidir.
OscarRyz

23
@vemv Evet, cevabı anlamak için önce soruyu okumalısın.
OscarRyz

200

Oscar'ın (hoş bir şekilde özlü!) Cevabına biraz ayrıntı eklemek için, Java Dil Spesifikasyonu ile ilgili bölüm 8.4.3.6, 'senkronize Yöntemler'dir :

Senkronize bir yöntem , yürütülmeden önce bir monitör ( §17.1 ) alır. Bir sınıf (statik) yöntemi için, yöntemin sınıfı için Class nesnesiyle ilişkili monitör kullanılır. Bir örnek yöntemi için, bununla ilişkili monitör (yöntemin çağrıldığı nesne) kullanılır.


17
Yararlı, o alıntıyı arıyordum +1
OscarRyz

80

Dikkat etmeniz gereken bir nokta (genellikle birkaç programcı bu tuzağa düşer), senkronize edilmiş statik yöntemler ile senkronize edilmiş statik olmayan yöntemler arasında hiçbir bağlantı olmamasıdır, yani:

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

Ana:

A a = new A();

Konu 1:

A.f();

Konu 2:

a.g();

f () ve g () birbiriyle senkronize değildir ve bu nedenle tamamen eşzamanlı olarak çalışabilir.


18
ama ya g (), f () 'nin okuduğu bir statik değişkeni mutasyona uğratıyorsa? Bu ipliği nasıl güvenli hale getireceğiz? O halde açıkça sınıf için bir kilit alıyor muyuz?
Baskın

22
Evet, statik olmayan yönteminizin sınıfın kendisi üzerinde açıkça senkronize olması gerekir (ör synchronized (MyClass.class) {...}.
jfpoilpret

@jfpoilpret "senkronize (MyClass.class) {...}", bu yöntemi statik olarak senkronize etmekle eşdeğerdir, değil mi?
crazymind

15

G () 'yi aşağıdaki gibi uygulamazsanız:

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

Bu modeli, nesnenin farklı örnekleri arasında karşılıklı dışlama uygulamak istediğimde de yararlı buluyorum (bu, örneğin bir dış kaynağa erişirken gereklidir).


63
Aslında burada bazı çok ince ve çirkin böceklerin olma ihtimali olabileceğini unutmayın. Remember çalışma zamanı türünü getClass()döndürür ; Sınıfı alt sınıfa ayırırsanız, üst sınıf ve alt sınıf farklı kilitlerde senkronize olur. tüm örneklerin aynı kilidi kullandığından emin olmanız gerekiyorsa, gidilecek yoldur. synchronized(MyClass.class)
Cowan

4

İçsel Kilitler ve Senkronizasyon ile ilgili oracle belgeleri sayfasına bir göz atın

Statik bir yöntem bir nesneyle değil, bir sınıfla ilişkilendirildiğinden, statik eşitlenmiş bir yöntem çağrıldığında ne olduğunu merak edebilirsiniz. Bu durumda, iş parçacığı, sınıfla ilişkili Class nesnesi için iç kilidi alır . Böylece, sınıfın statik alanlarına erişim, sınıfın herhangi bir örneği için kilitten farklı bir kilit tarafından kontrol edilir .


2

Statik bir yöntemin ayrıca ilişkili bir nesnesi vardır. JDK araç setindeki Class.class dosyasına aittir. .Class dosyası ram içine yüklendiğinde, Class.class bunun şablon nesnesi olarak adlandırılan bir örneğini oluşturur.

Örneğin: - gibi mevcut müşteri sınıfından nesne oluşturmaya çalıştığınızda

Customer c = new Customer();

Customer.class RAM'e yüklenir. O anda, JDK araç setindeki Class.class, Şablon nesnesi adında bir Nesne oluşturur ve bu Customer.class'ı bu şablon nesnesine yükler. Bu Customer.class'ın statik üyeleri, o şablon nesnesinde öznitelikler ve yöntemler haline gelir.

Dolayısıyla statik bir yöntem veya öznitelik de bir nesneye sahiptir.


2

Aşağıdaki örnekler, sınıf ve nesne kilidi arasında daha fazla netlik sağlar, umarım aşağıdaki örnek başkalarına da yardımcı olur :)

Örneğin, aşağıdaki yöntemlere sahibiz: biri sınıf edinir ve diğeri nesne kilidi alır:

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

Şimdi şu senaryolara sahip olabiliriz:

  1. Aynı Object kullanan evreler aynı anda objLock OR staticLock yöntemine erişmeye çalıştığında (yani her iki iş parçacığı da aynı yönteme erişmeye çalışıyor)

    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. Aynı Nesneyi kullanan evreler aynı anda erişmeye staticLockve objLockyöntemlere erişmeye çalıştığında (farklı yöntemlere erişmeye çalışır)

    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. Farklı Object kullanan evreler staticLockyönteme erişmeye çalıştığında

    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. Farklı Object kullanan evreler objLockyönteme erişmeye çalıştığında

    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

Statik eşitlenmiş yöntemi aşina olmayanlar için sınıf nesnesine kilitlenir, örneğin dizge sınıfı için String.class iken, eşzamanlı örnek yöntemi Java'da "this" anahtar sözcüğü ile belirtilen geçerli Object örneğini kilitler. Bu nesnelerin her ikisi de farklı olduğu için, farklı kilitlere sahip oldukları için, bir iş parçacığı statik eşitlenmiş yöntemi çalıştırırken, java'daki diğer iş parçacığının bu iş parçacığının geri dönmesini beklemesi gerekmez, bunun yerine bayt olarak belirtilen ayrı bir kilit elde eder. statik senkronize yöntem.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.