Ikke-blokkerende køer

Trådsikre og viktigst av alt ikke-blokkerende køimplementeringer på koblede noder.

ConcurrentLinkedQueue<E> - den bruker en ventefri algoritme tilpasset for å jobbe med søppelsamleren. Denne algoritmen er ganske effektiv og veldig rask, siden den er bygget på CAS. Size()- metodenkan kjøre i lang tid, så det er best å ikke trekke den hele tiden.

ConcurrentLinkedDeque<E> - Deque står for Double ended queue. Dette betyr at data kan legges til og trekkes fra begge sider. Følgelig støtter klassen begge driftsmodusene: FIFO (First In First Out) og LIFO (Last In First Out).

I praksis bør ConcurrentLinkedDeque brukes hvis LIFO er absolutt nødvendig, siden på grunn av toveisiteten til nodene, taper denne klassen halvparten i ytelse 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();
           }
       }
   }
}

Blokkering av køer

BlockingQueue<E> -grensesnitt - hvis det er mye data, er ikke ConcurrentLinkedQueue nok.

Når tråder ikke klarer jobben sin, kan du enkelt få en OutOfMemmoryException . Og for at slike tilfeller ikke skal oppstå, har vi en BlockingQueue for arbeid med tilstedeværelsen av forskjellige metoder for å fylle og jobbe med køen og betingede låser.

BlockingQueue gjenkjenner ikke null-elementer og kaster et NullPointerException når du prøver å legge til eller hente et slikt element. Avstemningsmetoden returnerer et null-element hvis intet element har blitt plassert i køen innen tidsavbruddet.

BlockingQueue<E>-implementeringer

La oss ta en nærmere titt på hver av våre BlockingQueue- implementeringer :

ArrayBlockingQueue<E> er en blokkerende køklasse bygget på den klassiske ringbufferen. Her har vi muligheten til å håndtere "ærligheten" til låser. Hvis fair=false (standard), er ikke trådbestilling garantert.

DelayQueue<E extends Delayed> er en klasse som lar deg trekke elementer fra køen bare etter en viss forsinkelse, definert i hvert element gjennom getDelay- metoden til Delayed - grensesnittet.

LinkedBlockingQueue<E> er en blokkeringskø på koblede noder, implementert på "to-låskø"-algoritmen: den første låsen er for å legge til, den andre er for å trekke et element fra køen. På grunn av låser, sammenlignet med ArrayBlockingQueue , har denne klassen høy ytelse, men den krever mer minne. Køstørrelsen angis via konstruktøren og er lik Integer.MAX_VALUE som standard.

PriorityBlockingQueue<E> er en flertråds wrapper over PriorityQueue . Komparatoren er ansvarlig for logikken som elementet vil bli lagt til. Det minste elementet kommer først ut.

SynchronousQueue<E> - køen fungerer etter FIFO (først-inn-først-ut)-prinsippet. Hver innsettingsoperasjon blokkerer "Produsent"-tråden til "Forbruker"-tråden trekker elementet fra køen og omvendt, "Forbruker" vil vente til "Produsent" setter inn elementet.

BlockingDeque<E> er et grensesnitt som beskriver tilleggsmetoder for en toveis blokkeringskø. Data kan settes inn og trekkes ut fra begge sider av køen.

LinkedBlockingDeque<E> er en toveis blokkeringskø på koblede noder, implementert som en enkel toveis liste med én lås. Køstørrelsen angis via konstruktøren og er lik Integer.MAX_VALUE som standard.

TransferQueue<E> - grensesnittet er interessant ved at når et element legges til køen, er det mulig å blokkere den innsatte Produsent- tråden til en annen Consumer- tråd trekker elementet fra køen. Du kan også legge til en sjekk for et bestemt tidsavbrudd eller sette en sjekk for ventende forbrukere . Som et resultat får vi en dataoverføringsmekanisme med støtte for asynkrone og synkrone meldinger.

LinkedTransferQueue<E> er en implementering av TransferQueue basert på Dual Queue with Slack-algoritmen. Bruker mye CAS (se over) og gjengeparkering når den ikke er i bruk.