SORU
31 AĞUSTOS 2008, Pazar


Java: () haber vs notifyAll() tekrar

Eğer biri için Googles "notify() notifyAll() arasındaki fark" sonra bir çok açıklama açılır (javadoc paragraf bırakmak dışında). Onu bekleyen iş uyanamama sayısı için aşağı kaynar: notify() notifyAll() hepsi bir arada.

Ancak (eğer ben anlamak arasındaki fark bu yöntemler sağda), yalnızca bir iş parçacığı her zaman seçili için daha fazla izleyici kazanılması; ilk durumda seçilen tarafından VM, ikinci durumda seçilen sistem iş zamanlayıcı. Her ikisi de (genel durumda) için tam seçme işlemleri programcı değildir.

Bu nediryararlınotify() notifyAll() arasındaki fark? Bir şey mi kaçırdım?

CEVAP
6 Temmuz 2010, Salı


Açıkça, notify uyanır (herhangi biri) bekle bir iş parçacığı, notifyAll bekleme kümesindeki tüm konuları uyanır ayarlayın. Aşağıdaki tartışma, herhangi bir şüphe temizlemek gerekir. notifyAll çoğu zaman kullanılmalıdır. Eğer kullanmak için hangi emin değilseniz, o zaman notifyAllkullanın.Aşağıdaki açıklamaya bakın lütfen.

Çok dikkatli okumak ve anlamak. Eğer herhangi bir sorunuz varsa bana e-posta gönderin.

Üretici/tüketici (varsayım iki yöntem ile ProducerConsumer bir sınıftır). KIRIK notify kullandığından () - Evet iş OLABİLİR - çoğu zaman bile, aynı zamanda kilitlenme - neden göreceğiz neden olabilir:

public synchronized void put(Object o) {
    while (buf.size()==MAX_SIZE) {
        wait(); // called if the buffer is full (try/catch removed for brevity)
    }
    buf.add(o);
    notify(); // called in case there are any getters or putters waiting
}

public synchronized Object get() {
    // Y: this is where C2 tries to acquire the lock (i.e. at the beginning of the method)
    while (buf.size()==0) {
        wait(); // called if the buffer is empty (try/catch removed for brevity)
        // X: this is where C1 tries to re-acquire the lock (see below)
    }
    Object o = buf.remove(0);
    notify(); // called if there are any getters or putters waiting
    return o;
}

ÖNCELİKLE

Neden döngü bekleme çevreleyen ihtiyacımız var mı?

Bu durum da gelirse diye: while bir döngüye ihtiyacımız var

Tüketici 1 (C1) senkronize blok girin ve Tampon boş, C1 bekle ayarlayın (wait çağrı) konur. Tüketici 2 (C2) senkronize yöntemi girmek üzere yukarıda Y noktası (), ama Yapımcı P1 tampon bir nesne koyar ve daha sonra notify çağırır. Sadece bekleyen iş parçacığı uyandı ve şimdi yeniden almaya çalışır yani C1, nesne noktada kilit X (yukarıda).

Şimdi C1 ve C2 senkronizasyon kilidi almak için çalışıyorsunuz. Bunlardan biri (nondeterministically) seçilir ve diğer engellendi yöntemi girer (bekleme - ama, bu yöntem üzerinde kilit almaya çalışırken engellendi. Hadi C2 ilk kilit alır söylüyorlar. C1 hala engelleme (X kilit almaya çalışırken). C2 yöntemi tamamlar ve kilidi serbest bırakır. Şimdi, C1 kilit satın aldı. Sanırım şanslı bir while döngü, çünkü, C1 gerçekleştiren döngü kontrol (bekçi) ve engel kaldırma varolmayan bir unsur arabellek (C2 aldım zaten!). Eğer bir zorluk varsa while, IndexArrayOutOfBoundsException C1 çalışır bir arabellek ilk öğe kaldırmak için almak istiyorsunuz!

ŞİMDİ

Tamam, şimdi neden notifyAll ihtiyacımız var mı?

Üretici/tüketici away notify ile alabiliriz gibi görünüyor yukarıdaki örnek. Üç muhafız kanıtlayabiliriz, çünkü bu şekilde görünüyorbekleüretici ve tüketici için döngüler birbirini dışlayan. Yani, sanki biz başka bir iş parçacığı bekleyen put yöntem olarak get yöntem, çünkü, o doğru, o zaman şu ki gerçek olmak zorunda:

buf.size() == 0 AND buf.size() == MAX_SIZE (farz MAX_SİZE 0 değil)

ANCAK, bu yeterince iyi değil, notifyAll kullanmamız GEREKİYOR. Neden izin bakın

Boyutu 1 buffer (örnek takip etmek kolay yapmak için) vardır. Aşağıdaki adımları bize çıkmaz yol. Bir konu haber ile uyandı ZAMAN, olmayan kararlı seçilen JVM ile herhangi bir bekleyen iş parçacığı uyandı olabilir. olabilir unutmayın. Aynı zamanda birden çok iş parçacığı bir yönteme giriş (kilit almaya çalışırken yani) engelleme olduğunda, satın alma siparişi non-deterministik olabilir. Hatırlıyorum da bir iş parçacığı sadece bir yöntem de herhangi bir zaman senkronize yöntemleri izin tek bir iplik olmak yürütme (yani holding kilit) (senkronize) yöntemleri sınıf. Eğer aşağıdaki olaylar dizisi oluşur - kilitlenme sonuçları:

ADIM 1:
Tampona - P1 koyar 1 char

ADIM 2:
- P2 denemeleri 22* * - bekle loop - zaten bir char - bekler denetler

ADIM 3:
- P3 girişimleri, 23* * - bekle loop - zaten bir char - bekler denetler

ADIM 4:
- C1 1 char almaya çalışır
- C2 1 char - get yöntemi için giriş bloklar almaya çalışır
- C3 1 char - get yöntemi için giriş bloklar almaya çalışır

ADIM 5:
- C1 get yöntem yürütme - char alır, notify, çıkış yöntemi çağırır
- notify P2 uyanır
- AMA, C2 girer put yöntemi P2 (P2 kilidi yeniden almak gerekir), giriş yani P2 blok önce yöntemi
- C2 döngü kontrolleri, tampon fazla karakter, bekler yani
- C3 P2, Çek bekle döngü, tampon fazla karakter, çok bekler önce C2, ama sonra yöntem girer

ADIM 6:
- ŞİMDİ: P3, C2, C3 bekliyor!
- Son olarak P2 kilit edinme, tampon bir char koyar, haber görüşmeleri, çıkış yöntemi

ADIM 7:
- P2, P3 bildirim (herhangi bir iş parçacığı uyandı olabilir unutmayın) uyandırır
- P3 denetler bekleme döngü koşulu, zaten tampon bir char var, çok bekler.
- HAYIR DAHA fazla iş PARÇACIĞI BİLDİRMEK ve ÜÇ KONULARI KALICI olarak ASKIYA arasın!

ÇÖZÜM: üretici/tüketici kodu notifyAll (yukarıda) ile notify Değiştirin.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • George McCarron

    George McCar

    29 Mayıs 2013
  • John Lynn

    John Lynn

    8 Ocak 2010
  • sk8ingis4me

    sk8ingis4me

    16 Mart 2006