ConcurrentLinkedQueue nasıl kullanılır?


96

ConcurrentLinkedQueueJava'da a'yı nasıl kullanırım ? Bunu
kullanarak LinkedQueuekuyruktaki eşzamanlılık konusunda endişelenmem gerekiyor mu? Yoksa sadece iki yöntem tanımlamam mı gerekiyor (biri listeden öğeleri geri almak için ve diğeri listeye öğeler eklemek için)?
Not: açıkça bu iki yöntemin senkronize edilmesi gerekir. Sağ?


DÜZENLEME: Yapmaya çalıştığım şey şudur: Sıradan öğeleri almak için bir yöntemi olan bir sınıfım (Java'da) ve sıraya öğe eklemek için bir yöntemi olan başka bir sınıfım var. Listeye eklenen ve listeden alınan öğeler kendi sınıfımın nesneleridir.

Bir soru daha: Bunu kaldırma yönteminde yapmam gerekir mi:

while (queue.size() == 0){ 
  wait(); 
  queue.poll();
}

Sadece bir tüketicim ve bir üreticim var.


Mt sorusuna verdiğiniz yanıt için teşekkürler. Yapmaya çalıştığım şey şudur: Kuyruktan öğeleri almak için bir yöntemi olan bir sınıfım (Java'da) ve sıraya öğe eklemek için bir yöntemi olan başka bir sınıfım var. Listeye eklenen ve listeden alınan öğeler kendi sınıfımın nesneleridir.
Ricardo Felgueiras

2
Sorunuzu düzenlemeli ve bu açıklamayı sorunun kendisine eklemelisiniz.
Adam Jaskiewicz

Yanıtlar:


157

Hayır, yöntemlerin eşitlenmesi gerekmez ve herhangi bir yöntem tanımlamanız gerekmez; zaten ConcurrentLinkedQueue'dalar, sadece onları kullanın. ConcurrentLinkedQueue, ihtiyacınız olan tüm kilitleme ve diğer işlemleri dahili olarak yapar; üreticiniz / üreticileriniz kuyruğa veri ekler ve tüketicileriniz bunun için anket yapar.

Önce sıranızı oluşturun:

Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>();

Şimdi, üretici / tüketici nesnelerinizi nerede yaratıyor olursanız olun, sıraya geçin, böylece nesnelerini koyabilecekleri bir yere sahip olurlar (bunun yerine bunun için bir ayarlayıcı kullanabilirsiniz, ancak ben bir kurucuda bu tür şeyler yapmayı tercih ederim):

YourProducer producer = new YourProducer(queue);

ve:

YourConsumer consumer = new YourConsumer(queue);

ve yapımcınıza bir şeyler ekleyin:

queue.offer(myObject);

ve tüketicinizdeki eşyaları çıkarın (kuyruk boşsa, anket () boş dönecektir, bu yüzden kontrol edin):

YourObject myObject = queue.poll();

Daha fazla bilgi için bkz . Javadoc

DÜZENLE:

Kuyruğun boş olmaması için beklemeyi engellemeniz gerekiyorsa, muhtemelen bir LinkedBlockingQueue ve take () yöntemini kullanmak istersiniz . Bununla birlikte, LinkedBlockingQueue maksimum kapasiteye sahiptir (varsayılan olarak Integer.MAX_VALUE şeklindedir, bu iki milyardan fazladır) ve bu nedenle koşullarınıza bağlı olarak uygun olabilir veya olmayabilir.

Kuyruğa bir şeyler koyan yalnızca bir iş parçacığınız varsa ve kuyruktan bir şeyler alan başka bir iş parçacığınız varsa, ConcurrentLinkedQueue muhtemelen gereğinden fazla olur. Sıraya aynı anda erişen yüzlerce hatta binlerce iş parçacığına sahip olabileceğiniz zamanlar için daha fazlası. İhtiyaçlarınız muhtemelen aşağıdakiler kullanılarak karşılanacaktır:

Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());

Bunun bir artısı, örneğe (kuyruk) kilitlenmesidir, böylece bileşik işlemlerin atomikliğini sağlamak için kuyrukta senkronizasyon yapabilirsiniz (Jared tarafından açıklandığı gibi). Tüm işlemler örnek üzerinde kilitleme OLMADAN (java.util.concurrent.atomic değişkenler kullanılarak) yapıldığından, bunu ConcurrentLinkedQueue ile YAPAMAZSINIZ. Kuyruk boşken bloke etmek istiyorsanız bunu yapmanıza gerek YOKTUR, çünkü poll () kuyruk boşken basitçe null döndürecektir ve anket () atomiktir. Anketin () boş döndürüp döndürmediğini kontrol edin. Varsa, bekleyin (), ardından tekrar deneyin. Kilitlemeye gerek yok.

En sonunda:

Dürüst olmak gerekirse, sadece LinkedBlockingQueue kullanırım. Başvurunuz için hala aşırı, ancak büyük olasılıkla iyi çalışacak. Yeterince performanslı değilse (PROFİL!), Her zaman başka bir şey deneyebilirsiniz ve bu, HERHANGİ bir senkronize şeyle uğraşmanıza gerek olmadığı anlamına gelir:

BlockingQueue<YourObject> queue = new LinkedBlockingQueue<YourObject>();

queue.put(myObject); // Blocks until queue isn't full.

YourObject myObject = queue.take(); // Blocks until queue isn't empty.

Diğer her şey aynı. Koyma muhtemelen engellemez, çünkü iki milyar nesneyi sıraya koyma ihtimaliniz yok.


Cevabınız için teşekkürler. Bir soru daha: Bunu kaldırma yönteminde yapmam gerekiyor mu: while (queue.size () == 0) wait (); queue.poll ();
Ricardo Felgueiras

Bunu cevabım için bir düzeltme olarak cevaplayacağım, çünkü oldukça önemli.
Adam Jaskiewicz

Başka bir soruda karışıklığa neden olduğu için, uygulanmayan Collection.synchronizedLista döndürür . ListQueue
Tom Hawtin - tackline

@AdamJaskiewicz, ConcurrentLinkedQueueÜretici Tüketici için iyi bir fikir kullanıyor, bu
gönderiye

37

Bu büyük ölçüde başka bir sorunun kopyasıdır .

İşte cevabın bu soruyla ilgili olan bölümü:

Java.util.ConcurrentLinkedQueue kullanırsam kendi senkronizasyonumu yapmam gerekir mi?

Eşzamanlı koleksiyonlardaki atomik işlemler sizin için senkronize edilir. Diğer bir deyişle, kuyruğa yapılan her bir çağrı, sizin herhangi bir işlem yapmanıza gerek kalmadan iş parçacığı açısından güvenli garantilidir. Ne olduğunu değil evreli olmayan atomiktir koleksiyonunda yaptığınız herhangi operasyonlardır garantili.

Örneğin, bu sizin herhangi bir işlem yapmadan iş parçacıklıdır:

queue.add(obj);

veya

queue.poll(obj);

Ancak; Kuyruğa yapılan atomik olmayan çağrılar otomatik olarak iş parçacığı açısından güvenli değildir. Örneğin, aşağıdaki işlemler otomatik olarak iş parçacığı güvenli değildir :

if(!queue.isEmpty()) {
   queue.poll(obj);
}

Sonuncusu, isEmpty'nin çağrıldığı ve anketin çağrıldığı zaman arasında, diğer iş parçacıklarının kuyruğa öğe eklemesi veya çıkarması çok olası olduğundan, iş parçacığı güvenli değildir. Bunu gerçekleştirmenin iş parçacığı güvenli yolu şudur:

synchronized(queue) {
    if(!queue.isEmpty()) {
       queue.poll(obj);
    }
}

Yine ... kuyruğa yapılan atomik çağrılar otomatik olarak iş parçacığı açısından güvenlidir. Atomik olmayan aramalar değil.


1
Yapabileceğim tek yaygın kullanım, sıra boş olmayana kadar engellemektir. BlockingQueue (take () atomiktir ve tüketilecek bir şey olana kadar bloklar) bir uygulama kullanılarak daha iyi sunulmaz mı?
Adam Jaskiewicz

6
Ayrıca buna dikkat etmelisin. Senkronize Listeden farklı olarak ConcurrentLinkedQueue kendi kendine senkronize olmaz, bu nedenle kodunuzda bir üreticinin siz senkronize edilmiş bloğunuzdayken kuyruğa teklif vermesi yine de mümkün olacaktır.
Adam Jaskiewicz

Queue.isEmpty () ve queue.poll () neden birleştirilir? Sadece anket yapıp sonucun boş olup olmadığını kontrol edemez misin? (Anladığım kadarıyla boş bir kuyruğu
yoklarsanız

Son kod bloğu hariç kodunuzdaki her şeye katılıyorum. ConcurrentLInkedQueue'da senkronizasyon, diğer çağrılar senkronize edilmediğinden size hiçbir şey garanti etmez. Böylece, bu konuyu senkronize etmiş olsanız bile "isEmpty ()" ve "anket (...)" arasında başka bir iş parçacığından bir "ekle (..)" olabilir
Klitos G.

6

İlk öğeyi almak için anketi kullanın ve yeni bir son öğe eklemek için ekleyin. İşte bu, senkronizasyon veya başka bir şey yok.


6

Kuyruktaki her şeyi tüketmeye çalışırken muhtemelen iş parçacığı güvenliği ve "güzelliği" açısından aradığınız şey budur:

for (YourObject obj = queue.poll(); obj != null; obj = queue.poll()) {
}

Bu, sıra boşken çıkmanızı ve boş olmadığı sürece nesneleri çıkarmaya devam etmenizi garanti eder.


Bir kuyruğu boşaltmak için çok kullanışlıdır. Teşekkürler.
DevilCode

2

ConcurentLinkedQueue çok verimli bir bekleme / kilitlemesiz uygulamasıdır (referans için javadoc'a bakın), bu nedenle yalnızca senkronize etmeniz gerekmiyor, aynı zamanda kuyruk hiçbir şeyi kilitlemeyecek, böylece neredeyse senkronize olmayan (iş parçacığı değil) kadar hızlı olacaktır. güvenli) bir.


1

Eşzamanlı olmayan bir koleksiyon gibi kullanın. Concurrent [Collection] sınıfları, erişimi senkronize etmeyi düşünmek zorunda kalmamanız için normal koleksiyonları sarar.

Düzenleme: ConcurrentLinkedList aslında sadece bir sarmalayıcı değil, daha iyi bir eşzamanlı uygulama. Her iki durumda da senkronizasyon konusunda endişelenmenize gerek yok.


ConcurrentLinkedQueue değildir. Birden çok üretici ve tüketici tarafından eşzamanlı erişim için sıfırdan özel olarak oluşturulmuştur. Collections.synchronized *
Adam Jaskiewicz

Evet, J2SE 5'te çok sayıda düzgün eşzamanlılık özelliği eklendi.
Adam Jaskiewicz
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.