Ikke-blokerende køer
Trådsikre og vigtigst af alt ikke-blokerende kø -implementeringer på sammenkædede noder.
ConcurrentLinkedQueue<E> - den bruger en ventefri algoritme tilpasset til at arbejde med skraldeopsamleren. Denne algoritme er ret effektiv og meget hurtig, da den er bygget på CAS. Size()- metodenkan køre i lang tid, så det er bedst ikke at trække den hele tiden.
ConcurrentLinkedDeque<E> - Deque står for Double ended queue. Det betyder, at data kan tilføjes og trækkes fra begge sider. Følgelig understøtter klassen begge driftstilstande: FIFO (First In First Out) og LIFO (Last In First Out).
I praksis bør ConcurrentLinkedDeque bruges, hvis LIFO er absolut nødvendigt, da denne klasse på grund af nodernes todirektionalitet mister halvdelen i ydeevne sammenlignet med ConcurrentLinkedQueue .
import java.util.concurrent.ConcurrentLinkedQueue;
public class ConcurrentLinkedQueueExample {
public static void main(String[] args) {
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
Thread producer = new Thread(new Producer(queue));
Thread consumer = new Thread(new Consumer(queue));
producer.start();
consumer.start();
}
}
class Producer implements Runnable {
ConcurrentLinkedQueue<String> queue;
Producer(ConcurrentLinkedQueue<String> queue){
this.queue = queue;
}
public void run() {
System.out.println("Class for adding items to the queue");
try {
for (int i = 1; i < 5; i++) {
queue.add("Item #" + i);
System.out.println("Added: Item #" + i);
Thread.sleep(300);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
class Consumer implements Runnable {
ConcurrentLinkedQueue<String> queue;
Consumer(ConcurrentLinkedQueue<String> queue){
this.queue = queue;
}
public void run() {
String str;
System.out.println("Class for getting items from the queue");
for (int x = 0; x < 5; x++) {
while ((str = queue.poll()) != null) {
System.out.println("Pulled out: " + str);
}
try {
Thread.sleep(600);
} catch (InterruptedException ex) {
ex.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
}
Blokering af køer
BlockingQueue<E> interface - hvis der er mange data, er ConcurrentLinkedQueue ikke nok.
Når tråde ikke klarer deres arbejde, kan du nemt få en OutOfMemmoryException . Og for at sådanne sager ikke opstår, har vi en BlockingQueue til arbejde med tilstedeværelsen af forskellige metoder til at udfylde og arbejde med køen og betingede låse.
BlockingQueue genkender ikke null-elementer og kaster en NullPointerException , når du forsøger at tilføje eller hente et sådant element. Afstemningsmetoden returnerer et null-element, hvis intet element er blevet placeret i køen inden for timeout.
BlockingQueue<E>-implementeringer
Lad os se nærmere på hver af vores BlockingQueue- implementeringer :
ArrayBlockingQueue<E> er en blokerende køklasse bygget på den klassiske ringbuffer. Her har vi mulighed for at styre låses “ærlighed”. Hvis fair=false (standard), så er trådbestilling ikke garanteret.
DelayQueue<E extends Delayed> er en klasse, der giver dig mulighed for kun at trække elementer fra køen efter en vis forsinkelse, defineret i hvert element gennem getDelay- metoden i Delayed- grænsefladen.
LinkedBlockingQueue<E> er en blokeringskø på sammenkædede noder, implementeret på "two lock queue"-algoritmen: den første lås er til at tilføje, den anden er til at trække et element fra køen. På grund af låse, sammenlignet med ArrayBlockingQueue , har denne klasse høj ydeevne, men den kræver mere hukommelse. Køstørrelsen indstilles via konstruktøren og er som standard lig med Integer.MAX_VALUE.
PriorityBlockingQueue<E> er en multi-threaded wrapper over PriorityQueue . Komparatoren er ansvarlig for logikken, hvorved elementet tilføjes. Det mindste element kommer først ud.
SynchronousQueue<E> - køen fungerer efter FIFO (first-in-first-out) princippet. Hver indsættelsesoperation blokerer "Producer"-tråden, indtil "Forbruger"-tråden trækker elementet fra køen og omvendt, vil "Forbruger" vente, indtil "Producer" indsætter elementet.
BlockingDeque<E> er en grænseflade, der beskriver yderligere metoder til en tovejs blokeringskø. Data kan indsættes og trækkes ud fra begge sider af køen.
LinkedBlockingDeque<E> er en tovejs blokeringskø på sammenkædede noder, implementeret som en simpel tovejsliste med én lås. Køstørrelsen indstilles via konstruktøren og er som standard lig med Integer.MAX_VALUE.
TransferQueue<E> - grænsefladen er interessant ved, at når et element tilføjes til køen, er det muligt at blokere den indsættende Producer- tråd , indtil en anden forbrugertråd trækker elementet fra køen. Du kan også tilføje en check for en bestemt timeout eller indstille en check for ventende forbrugere . Som et resultat får vi en dataoverførselsmekanisme med understøttelse af asynkrone og synkrone beskeder.
LinkedTransferQueue<E> er en implementering af TransferQueue baseret på Dual Queue med Slack-algoritmen. Gør stor brug af CAS (se ovenfor) og gevindparkering i tomgang.
GO TO FULL VERSION