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
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 notifyAll
kullanı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.
Java'da basit bir yolu, bir Dize tekra...
Basit bir senaryo bekle kullanarak() h...
Java dizeleri dizileri tekrar çıkartab...
Neden bekle() haber() Java'in Nes...
Java "-by pass-başvuru" veya...