Aynı sınıfta iki yöntemi senkronize edersem, aynı anda çalışabilirler mi?


164

Aynı sınıfta iki yöntemi senkronize edersem , aynı nesne üzerinde aynı anda çalışabilirler mi? Örneğin:

class A {
    public synchronized void methodA() {
        //method A
    }

    public synchronized void methodB() {
        // method B
    }
}

methodA()İki farklı iş parçacığında aynı nesne üzerinde iki kez çalışamayacağımı biliyorum . aynı şey methodB().

Ama hala çalışırken methodB()farklı iş parçacığında methodA()çalışabilir miyim? (aynı nesne)

Yanıtlar:


148

Her iki yöntem de aynı monitörü kilitler. Bu nedenle, bunları aynı iş parçacığında farklı iş parçacıklarından aynı anda çalıştıramazsınız (iki yöntemden biri diğeri bitene kadar engellenir).


1
Bu soruya bir ekleme yaptım. Her iki yöntemin de statik olduğunu varsayalım şimdi methodA Sınıf kullanılarak çağrılırken, methodB, t1'de A.methodA () ve t2'de obj.methodB () gibi bir nesne kullanılarak çağrılır. Şimdi ne olacak, engelleyecekler mi ????
Mart'ta

2
@ amod0017: obj.methodB()eşanlamlıdır A.methodB()zaman methodB()olduğu static. Bu nedenle evet, bloke ederler (nesnenin monitöründe değil, sınıfta).
NPE

dener ve ona geri döner. :)
Mart'ta

@NPE Bu nedenle, her iki yöntem de statik olsa ve aynı nesnede 2 t1 ve t2 iş parçacığı aynı anda methodA () ve methodB () öğesini çağırmaya çalışsa bile, yalnızca 1 (t1 diyelim) iş parçacığı yürütülür ve diğer iş parçacığı t1 kilidi serbest bırakana kadar beklemek zorundadır ?
sreeprasad

8
Statik yöntemlerin .classnesne üzerinde kilit kullandığını unutmayın . Eğer varsa class A {static synchronized void m() {} }. Ve sonra bir iş parçacığı new A().m()onu new A()nesneye kilit alır çağırır . O zaman başka bir iş parçacığı çağırır A.m(), YÖNTEM SORUN GİRMEZ çünkü hiçbir şey bu tür bir kilit sahipA.class iken , nesne üzerinde kilit olmasıdır . Bu yüzden yöntem beyan etmiş olsanız bile synchronized, aslında AYNI ZAMAN iki farklı iş parçacığı tarafından erişilir . Böylece: statik yöntemleri çağırmak için asla nesne referanslarını kullanmayın
Alex Semeniuk

113

Örnekte methodA ve methodB, örnek yöntemlerdir (statik yöntemlerin aksine). synchronizedBir örnek yöntemi koymak , iş parçacığının o yöntemdeki herhangi bir kodu yürütmeye başlayabilmesi için, yöntemin çağrıldığı nesne örneği üzerindeki iş parçacığının kilidini ("iç kilit") alması gerektiği anlamına gelir.

Eşitlenmiş olarak işaretlenmiş iki farklı örnek yönteminiz varsa ve farklı iş parçacıkları aynı yöntemleri aynı anda çağırıyorsa, bu iş parçacıkları aynı kilit için yarışacaktır. Bir iş parçacığı kilidi aldığında, diğer tüm iş parçacıkları o nesnedeki tüm senkronize edilmiş örnek yöntemlerinden kapatılır.

İki yöntemin aynı anda çalışması için farklı kilitler kullanmaları gerekir, örneğin:

class A {
    private final Object lockA = new Object();
    private final Object lockB = new Object();

    public void methodA() {
        synchronized(lockA) {
            //method A
        }
    }

    public void methodB() {
        synchronized(lockB) {
            //method B
        }
    }
}

burada senkronize blok sözdizimi, bloğa girmek için yürütme iş parçacığının kendinden kilit alması gereken belirli bir nesnenin belirlenmesine izin verir.

Anlaşılması gereken önemli şey, bireysel yöntemlere "senkronize" bir anahtar kelime koymamıza rağmen, temel kavramın perde arkasındaki yapısal kilit olmasıdır.

Java öğreticisinin ilişkiyi nasıl tanımladığı aşağıda açıklanmıştır:

Senkronizasyon, kendinden kilitli veya monitör kilidi olarak bilinen bir iç varlık etrafında oluşturulur. (API spesifikasyonu genellikle bu varlığı basitçe bir "monitör" olarak ifade eder.) İçsel kilitler senkronizasyonun her iki yönünde de rol oynar: bir nesnenin durumuna özel erişim sağlamak ve görünürlük için gerekli olan ilişkiden önce ilişkiler kurmak.

Her nesnenin kendisiyle ilişkilendirilmiş kendinden kilit vardır. Kural olarak, bir nesnenin alanlarına özel ve tutarlı erişime ihtiyaç duyan bir iş parçacığının, nesneye erişmeden önce kendinden kilit alması ve daha sonra kendisiyle tamamlandığında iç kilidi açması gerekir. Bir ipliğin, kilidi edindiği ve kilidi serbest bıraktığı zaman arasında içsel kilide sahip olduğu söylenir. Bir iş parçacığının kendinden kilitlemesine sahip olduğu sürece, başka hiçbir iş parçacığı aynı kilidi alamaz. Diğer iş parçacığı, kilidi almaya çalıştığında engellenir.

Kilitlemenin amacı paylaşılan verileri korumaktır. Yalnızca her bir kilit farklı veri üyelerini koruduysa, yukarıdaki örnek kodda gösterildiği gibi ayrı kilitler kullanırsınız.


yani bu örnekte kilit A sınıfı üzerinde değil, lockA \ lockB nesnelerinde mi? Bu bir sınıf seviyesi kilitleme örneği mi?
Nemrut

2
@Nimrod: lockA ve lockB nesnelerine kilitleniyor, A örneğine değil. Burada hiçbir şey bir sınıfa kilitlenmiyor. sınıf düzeyinde kilitleme, benzer bir şey kullanarak bir sınıf nesnesinin kilidini almak anlamına gelir static synchronizedveyasynchronized (A.class)
Nathan Hughes

İşte tam olarak burada neyin cevaplandığını açıklayan java öğreticisinin bağlantısı .
Alberto de Paola

18

Java Thread , bir örnek senkronize java yöntemine girdiğinde bir nesne düzeyinde kilit alır ve statik senkronize java yöntemine girdiğinde bir sınıf düzeyinde kilit alır .

Sizin durumunuzda, yöntemler (örnek) aynı sınıftadır. Böylece, bir iş parçacığı java senkronize yöntemine veya bloğuna girdiğinde bir kilit (yöntemin çağrıldığı nesne) elde eder. Dolayısıyla, ilk yöntem tamamlanana ve lock (nesnede) serbest bırakılana kadar aynı nesne üzerinde aynı anda başka yöntem çağrılamaz.


sınıfın iki farklı örneği üzerinde iki iş parçacığı varsa, o zaman bir iş parçacığı bir eşitlenmiş yöntemi çağırır ve diğeri ikinci eşitlenmiş yöntemi çağırır her iki yöntemi aynı anda yürütmek mümkün olacak. Anlayışım doğruysa private final Object lock = new object();, yalnızca bir iş parçacığının yöntemlerden birini yürütmesine izin vermek için senkronize ile kullanabilir miyim? Teşekkürler
Yug Singh

13

Sizin durumunuzda, aynı sınıf örneğinde iki yöntemi senkronize ettiniz. Bu nedenle, bu iki yöntem aynı sınıf A örneğinin farklı iş parçacığında aynı anda çalışamaz, ancak farklı sınıf A örneklerinde çalışabilir.

class A {
    public synchronized void methodA() {
        //method A
    }
}

aynıdır:

class A {
    public void methodA() {
        synchronized(this){
            // code of method A
        }
    }
}

ya bir kilidi tanımlayıp private final Object lock = new Object();şimdi locksenkronize blokla iki yöntemle kullanırsam ifadeniz doğru olur mu? Nesne tüm nesnelerin üst sınıfı olduğundan, iş parçacıkları sınıfın farklı örneğinde olsa bile, bir kerede yalnızca bir tanesi eşitlenmiş blok içindeki koda erişebilir. Teşekkürler.
Yug Singh

Sınıfta "özel son Nesne kilidi" tanımlar ve onunla senkronize ederseniz, sınıf örneği başına kilit var, böylece senkronize (aynı) davranır.
Oleksandr_DJ

Evet, Object tüm sınıflar için bir üst öğedir, ancak durumunuzdaki "lock" örneği "sahip olan sınıf başına örnek" tir, bu nedenle senkronizasyon için "this" ile aynı etkiye sahiptir.
Oleksandr_DJ

7

Oracle Belgelendirme Bağlantısından

Yöntemleri senkronize etmenin iki etkisi vardır:

İlk olarak, aynı nesne üzerinde senkronize yöntemlerin iki çağrılması için serpiştirmek mümkün değildir. Bir iş parçacığı bir nesne için eşitlenmiş bir yöntem yürütürken, aynı iş parçacığı için eşitleme yöntemlerini çağıran diğer tüm iş parçacıkları, ilk iş parçacığı nesne ile yapılana kadar.

İkincisi, senkronize edilmiş bir yöntem çıktığında, otomatik olarak aynı nesne için senkronize edilmiş bir yöntemin herhangi bir çağrılmasıyla önce gerçekleşen bir ilişki kurar. Bu, nesnenin durumundaki değişikliklerin tüm iş parçacıkları tarafından görülebilir olmasını sağlar

Bu, sorunuza cevap verecektir: Aynı nesnede, ilk senkronize yöntem yürütmesi devam ederken ikinci senkronize yöntemi çağıramazsınız.

İçsel kilitleri ve kilit davranışını anlamak için bu dokümantasyon sayfasına bakınız .


6

Kodunuzu aşağıdaki kod gibi düşünün:

class A {

public void methodA() {
    synchronized(this){        
      //method A body
    }
}

public void methodB() {
    synchronized(this){
      // method B body
    }
}

Yani, yöntem düzeyinde senkronize edilmesi basitçe senkronize edilmiş demektir (bu). herhangi bir iş parçacığı bu sınıfın bir yöntemini çalıştırırsa, yürütmeyi başlatmadan önce kilidi alır ve yöntemin yürütülmesi bitene kadar onu tutar.

Ancak methodA () hala çalışırken farklı bir iş parçacığında methodB () çalıştırabilir miyim? (aynı nesne)

Gerçekten de mümkün değil!

Bu nedenle, birden çok iş parçacığı aynı nesne üzerinde aynı anda herhangi bir sayıda eşitlenmiş yöntemi çalıştıramaz.


aynı sınıftan iki farklı nesne üzerinde Konu oluşturursam ne olur? Bu durumda bir iş parçacığından bir yöntem ve ikinci iş parçacığından başka bir yöntem çağırırsanız, aynı anda yürütülmez mi?
Yug Singh

2
Farklı nesneler oldukları için yapacaklar. Yani, bunu önlemek istiyorsanız, statik yöntemleri kullanabilir ve sınıfı senkronize edebilir veya bir sınıf değişkeni nesnesini kilit olarak kullanabilir veya sınıfı Singleton yapabilirsiniz. @Yug Singh
Khosro Makari

4

Açıkçası, hem statik senkronize hem de statik olmayan senkronize metodun eşzamanlı veya eşzamanlı olarak çalışması mümkündür, çünkü biri nesne seviye kilidine ve diğer sınıf seviyesi kilidine sahiptir.


3

Anahtar kolayca batmaz senkronizasyon ile fikir yöntemler üzerinde denir yalnızca etkiye sahip olmasıdır aynı nesne zaten cevapları ve yorumlarda vurgulanmıştır - örneğin -

Aşağıdaki örnek program açıkça belirtmek içindir -

public class Test {

public synchronized void methodA(String currentObjectName) throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA out");
}

public synchronized void methodB(String currentObjectName)  throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB out");
}

public static void main(String[] args){
    Test object1 = new Test();
    Test object2 = new Test();
    //passing object instances to the runnable to make calls later
    TestRunner runner = new TestRunner(object1,object2);
    // you need to start atleast two threads to properly see the behaviour
    Thread thread1 = new Thread(runner);
    thread1.start();
    Thread thread2 = new Thread(runner);
    thread2.start();
}
}

class TestRunner implements Runnable {
Test object1;
Test object2;

public TestRunner(Test h1,Test h2) {
    this.object1 = h1;
    this.object2 = h2;
}

@Override
public void run() {
    synchronizedEffectiveAsMethodsCalledOnSameObject(object1);
    //noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(object1,object2);
}

// this method calls the method A and B with same object instance object1 hence simultaneous NOT possible
private void synchronizedEffectiveAsMethodsCalledOnSameObject(Test object1) {
    try {
        object1.methodA("object1");
        object1.methodB("object1");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

// this method calls the method A and B with different object instances object1 and object2 hence simultaneous IS possible
private void noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(Test object1,Test object2) {
    try {
        object1.methodA("object1");
        object2.methodB("object2");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

İzin nasıl eşzamanlı erişim çıktısında farka dikkat edin beklendiği gibi yöntemler farklı nesne örneklerinde denir eğer.

İle Çıkışı noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects () yorumladı -the çıkış Yöntemib Out> içinde Yöntemia Out .. Yöntemib> sipariş Yöntemia içindedir * NoEffectOfSynchronizedAsMethodsCalledOnDifferentObjects () * ile çıkış

ve synthesizedEffectiveAsMethodsCalledOnSameObject () ile Ouput yorumladı - çıktı vurgulanan bölümde Thread1 ve Thread0 tarafından yöntemA'nın aynı anda erişimini gösterir -

* SynizedEffectiveAsMethodsCalledOnSameObject () * ile çıkış yorumladı

Diş sayısının arttırılması, dişi daha da belirgin hale getirecektir.


2

Hayır, bu mümkün değilse, her iki yöntem de aynı değişkeni aynı anda güncellemekte ve bu da verileri kolayca bozabilmektedir.


2

Evet, her iki iş parçacığını aynı anda çalıştırabilirler. Her nesne yalnızca bir kilit içerdiğinden ve her senkronize yöntem kilit gerektirdiğinden sınıfın 2 nesnesini oluşturursanız. Eşzamanlı olarak çalıştırmak istiyorsanız, iki nesne oluşturun ve bu nesne başvurusunu kullanarak çalıştırmayı deneyin.


1

Sınıfta olmayan bir nesne üzerinde senkronize edersiniz. Böylece aynı nesnede aynı anda çalışamazlar


0

Tek bir nesne üzerinde ortak bir senkronize yöntem uygulayan iki farklı iş parçacığı, nesne aynı olduğundan, bir iş parçacığı onu eşitlenmiş yöntemle kullandığında, kilidi değiştirmeniz gerekir, kilit etkinleştirilirse, bu iş parçacığı bekleme durumuna geçer, kilit devre dışıysa, nesneye erişebilir, erişirken kilidi etkinleştirir ve kilidi yalnızca yürütme tamamlandığında serbest bırakır. başka bir iş parçacığı geldiğinde, kilidi değiştirir, çünkü etkinleştirildiğinden, ilk iş parçacığının yürütülmesini tamamlamasını ve nesneye konulan kilidi serbest bırakmasını bekler, kilit serbest bırakıldıktan sonra ikinci iş parçacığı nesneye erişir ve kilit, yürütülene kadar etkinleştirir. dolayısıyla yürütme eşzamanlı olmayacak, her iki iş parçacığı tek tek yürütülecek,


1
Lütfen bu karışıklığı doğru bir şekilde noktalayın ve büyük harflerle yazın. 'Varify' diye bir kelime yok.
Lorne Marquis
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.