Jak używać ConcurrentLinkedQueue
w Javie?
Używając tego LinkedQueue
, czy muszę się martwić o współbieżność w kolejce? Czy muszę po prostu zdefiniować dwie metody (jedną do pobierania elementów z listy, a drugą do dodawania elementów do listy)?
Uwaga: oczywiście te dwie metody muszą być zsynchronizowane. Dobrze?
EDYCJA: To, co próbuję zrobić, to to: mam klasę (w Javie) z jedną metodą pobierania elementów z kolejki i inną klasą z jedną metodą dodawania elementów do kolejki. Elementy dodane i pobrane z listy są obiektami mojej własnej klasy.
Jeszcze jedno pytanie: czy muszę to zrobić w metodzie usuwania:
while (queue.size() == 0){
wait();
queue.poll();
}
Mam tylko jednego konsumenta i jednego producenta.
java
concurrency
Ricardo Felgueiras
źródło
źródło
Odpowiedzi:
Nie, metody nie muszą być synchronizowane i nie musisz definiować żadnych metod; są już w ConcurrentLinkedQueue, po prostu ich używaj. ConcurrentLinkedQueue wykonuje wewnętrznie wszystkie operacje blokowania i inne potrzebne; Twoi producenci dodają dane do kolejki, a Twoi konsumenci sondują je.
Najpierw utwórz kolejkę:
Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>();
Teraz, gdziekolwiek tworzysz swoje obiekty producenta / konsumenta, przekaż kolejkę, aby mieli gdzie umieścić swoje obiekty (zamiast tego możesz użyć do tego ustawiacza, ale ja wolę zrobić to w konstruktorze):
YourProducer producer = new YourProducer(queue);
i:
YourConsumer consumer = new YourConsumer(queue);
i dodaj do tego rzeczy w swoim producencie:
i wyjmij rzeczy z twojego konsumenta (jeśli kolejka jest pusta, poll () zwróci null, więc sprawdź to):
Aby uzyskać więcej informacji, zobacz Javadoc
EDYTOWAĆ:
Jeśli chcesz zablokować oczekiwanie, aż kolejka nie będzie pusta, prawdopodobnie chcesz użyć LinkedBlockingQueue i metody take (). Jednak LinkedBlockingQueue ma maksymalną pojemność (domyślnie Integer.MAX_VALUE, czyli ponad dwa miliardy), a zatem może być odpowiedni lub nie w zależności od okoliczności.
Jeśli masz tylko jeden wątek, który umieszcza rzeczy w kolejce, a inny wątek pobiera rzeczy z kolejki, ConcurrentLinkedQueue jest prawdopodobnie przesadą. Jest to bardziej przydatne, gdy możesz mieć setki lub nawet tysiące wątków uzyskujących dostęp do kolejki w tym samym czasie. Twoje potrzeby prawdopodobnie zostaną zaspokojone poprzez zastosowanie:
Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());
Zaletą tego jest to, że blokuje się na instancji (kolejce), dzięki czemu można synchronizować w kolejce, aby zapewnić atomowość operacji złożonych (jak wyjaśnił Jared). NIE MOŻESZ tego zrobić z ConcurrentLinkedQueue, ponieważ wszystkie operacje są wykonywane BEZ blokowania instancji (przy użyciu zmiennych java.util.concurrent.atomic). NIE będziesz musiał tego robić, jeśli chcesz blokować, gdy kolejka jest pusta, ponieważ funkcja poll () zwróci wartość null, gdy kolejka jest pusta, a funkcja poll () jest atomowa. Sprawdź, czy poll () zwraca null. Jeśli tak, poczekaj () i spróbuj ponownie. Nie ma potrzeby blokowania.
Wreszcie:
Szczerze, po prostu użyłbym LinkedBlockingQueue. Nadal jest to przesada dla twojej aplikacji, ale są szanse, że będzie działać dobrze. Jeśli nie jest wystarczająco wydajny (PROFIL!), Zawsze możesz spróbować czegoś innego, a to oznacza, że nie musisz zajmować się ŻADNYMI zsynchronizowanymi rzeczami:
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.
Cała reszta jest taka sama. Opcja Put prawdopodobnie nie zostanie zablokowana, ponieważ prawdopodobnie nie umieścisz dwóch miliardów obiektów w kolejce.
źródło
Collection.synchronizedList
zwraca a,List
które nie implementujeQueue
.ConcurrentLinkedQueue
dla Producer Consumer dobrego pomysłu, odnoszę się do tego posta stackoverflow.com/questions/1426754/ ...W dużej mierze jest to duplikat innego pytania .
Oto sekcja tej odpowiedzi, która ma znaczenie dla tego pytania:
Czy muszę wykonywać własną synchronizację, jeśli używam java.util.ConcurrentLinkedQueue?
Operacje atomowe na współbieżnych kolekcjach są synchronizowane za Ciebie. Innymi słowy, każde indywidualne wywołanie kolejki jest gwarantowane jako bezpieczne wątkowo bez żadnej akcji z Twojej strony. Co jest nie gwarantuje bezpieczny wątku są wszelkie operacje wykonać na zbiorach, które są non-atomowych.
Na przykład jest to ochrona wątków bez żadnej akcji z Twojej strony:
lub
Jednak; Nieatomowe wywołania kolejki nie są automatycznie bezpieczne dla wątków. Na przykład następujące operacje nie są automatycznie chronione wątkami:
if(!queue.isEmpty()) { queue.poll(obj); }
Ten ostatni nie jest bezpieczny dla wątków, ponieważ jest bardzo możliwe, że między wywołaniem isEmpty a wywołaniem sondażu inne wątki będą miały dodawane lub usuwane elementy z kolejki. Bezpieczny wątek sposób na to wygląda następująco:
synchronized(queue) { if(!queue.isEmpty()) { queue.poll(obj); } }
Ponownie ... niepodzielne wywołania kolejki są automatycznie bezpieczne dla wątków. Wezwania nieatomowe nie są.
źródło
Użyj ankiety, aby uzyskać pierwszy element, i dodaj, aby dodać nowy ostatni element. To wszystko, bez synchronizacji ani nic innego.
źródło
Prawdopodobnie właśnie tego szukasz pod względem bezpieczeństwa wątków i „ładności”, gdy próbujesz skonsumować wszystko w kolejce:
for (YourObject obj = queue.poll(); obj != null; obj = queue.poll()) { }
Gwarantuje to, że wyjdziesz, gdy kolejka jest pusta, i będziesz nadal usuwać z niej obiekty, o ile nie jest pusta.
źródło
ConcurentLinkedQueue to bardzo wydajna implementacja bez czekania / blokowania (zobacz javadoc w celach informacyjnych), więc nie tylko nie musisz synchronizować, ale kolejka niczego nie blokuje, dzięki czemu jest praktycznie tak szybka jak niezsynchronizowana bezpieczny) jeden.
źródło
Po prostu używaj go tak, jak kolekcji niewspółbieżnej. Klasy Concurrent [Collection] opakowują zwykłe kolekcje, dzięki czemu nie trzeba myśleć o synchronizacji dostępu.
Edycja: ConcurrentLinkedList nie jest w rzeczywistości tylko opakowaniem, ale raczej lepszą współbieżną implementacją. Tak czy inaczej, nie musisz się martwić o synchronizację.
źródło