2014-10-21 5 views
7

I eine Datenstruktur, wie diese haben Elemente aus einer Warteschlange in Java entfernen:Wie mit einer Schleife

Blocking mailbox = new LinkedBlockingQueue();

Ich versuche, dies zu tun:

for(Mail mail: mailbox) 
{ 
    if(badNews(mail)) 
    { 
     mailbox.remove(mail); 
    } 
} 

Offensichtlich wird der Inhalt der Schleife stören die Grenzen und ein Fehler ausgelöst wird, so würde ich diese normalerweise tun:

for(int i = 0; i < mailbox.size(); i++) 
{ 
    if(badNews(mailbox.get(i))) 
    { 
     mailbox.remove(i); 
     i--; 
    } 
} 

Aber leider haben BlockingQueue's keine Funktion, um ein Element per Index zu bekommen oder zu entfernen, also bleibe ich stecken. Irgendwelche Ideen?

Edit - Ein paar Erläuterungen: Eines meiner Ziele ist die Aufrechterhaltung der gleichen Reihenfolge so aus dem Kopf popping und es zurück in den Schwanz setzen ist nicht gut. Auch wenn keine anderen Threads E-Mails aus einem Postfach entfernen, werden sie hinzugefügt, sodass ich mich nicht in der Mitte eines Entfernungsalgorithmus befinden möchte, dass jemand mir eine E-Mail sendet und dann eine Ausnahme auftritt.

Vielen Dank im Voraus!

+0

Überprüfen Sie die Antwort, die ich gepostet habe. – UDPLover

Antwort

3

Sie können alle Elemente in Ihrer Warteschlange p̶o̶p̶ poll und p̶u̶s̶h̶ offer bearbeiten, bis Sie eine vollständige Schleife über Ihre Warteschlange erstellt haben. Hier ein Beispiel:

Mail firstMail = mailbox.peek(); 
Mail currentMail = mailbox.pop(); 
while (true) { 
    //a base condition to stop the loop 
    Mail tempMail = mailbox.peek(); 
    if (tempMail == null || tempMail.equals(firstMail)) { 
     mailbox.offer(currentMail); 
     break; 
    } 
    //if there's nothing wrong with the current mail, then re add to mailbox 
    if (!badNews(currentMail)) { 
     mailbox.offer(currentMail); 
    } 
    currentMail = mailbox.poll(); 
} 

Beachten Sie, dass dieser Ansatz nur funktioniert, wenn dieser Code in einem einzigen Thread ausgeführt wird, und es gibt keinen anderen Thread, die Elemente aus dieser Warteschlange entfernt.

Vielleicht müssen Sie überprüfen, ob Sie wirklich die Elemente aus der BlockingQueue abfragen wollen. Ähnlich für Angebot und Put.

Weitere Informationen:


Ein weiterer kleiner Buggy Ansatz eine temporäre Sammlung verwendet, nicht notwendigerweise gleichzeitig, und speichern Sie die Elemente, die Sie noch in der Notwendigkeit Warteschlange. Hier ist ein Kickoff-Beispiel:

List<Mail> mailListTemp = new ArrayList<>(); 
while (mailbox.peek() != null) { 
    Mail mail = mailbox.take(); 
    if (!badNews(mail)) { 
     mailListTemp.add(mail); 
    } 
} 
for (Mail mail : mailListTemp) { 
    mailbox.offer(mail); 
} 
+0

@ScaryWombat * behoben *. OP benachrichtigt uns jedoch nicht, wenn andere Threads auch Elemente aus der Warteschlange entfernen. –

+0

@ScaryWombat gut, ich lese keine andere vorherige Frage, so fehlt mir dieser Kontext. –

+0

Vielleicht verpasse ich Ihren Punkt, aber 'peek' gibt null zurück, wenn die Warteschlange leer ist (nicht blockierend)? Wenn in Ihrer vorherigen Version die Warteschlange leer war, bevor Sie in Ihre Schleife eingetreten sind, hätte sie eine NPE geworfen. –

0

Ich schaute über die Lösungen geschrieben und ich denke, ich fand eine Version, die meine Zwecke erfüllt. Was denkst du über diesen?

int size = mailbox.size(); 
for(int i = 0; i < size; i++) 
{ 
    Mail currentMail = mailbox.poll(); 
    if (!badNews(currentMail)) 
     mailbox.offer(currentMail); 
} 

Edit: Eine neue Lösung, die problemlos sein kann. Was denkt ihr?

while(true) 
{ 
    boolean badNewRemains = false; 

    for(Mail mail: mailbox) 
    { 
     if(badNews(mail)) 
     { 
      badNewRemains = true; 
      mailbox.remove(mail); 
      break; 
     } 
    } 

    if(!badNewRemains) 
     break; 
} 
+0

Die Größe der Warteschlange kann sich ändern, da andere Threads der Warteschlange mehr E-Mails hinzufügen. Sei vorsichtig damit. –

+0

Ja, jetzt sehe ich, dass die Elemente aus der Reihenfolge sein können, wenn neue Daten in der Mitte ankommen. Ich habe es oben noch einmal versucht. – Josh

0

Sie können die Warteschlange für Ihren Bedarf einfach implementieren. Und Sie müssen, wenn die API nicht über solche Funktionen verfügt.

One wie:

import java.util.Iterator; 
import java.util.LinkedList; 


class Mail { 
    boolean badMail; 
} 

class MailQueue { 
    private LinkedList<Mail> backingQueue = new LinkedList<>(); 
    private final Object lock = new Object(); 

    public void push(Mail mail){ 
     synchronized (lock) { 
      backingQueue.addLast(mail); 
      if(backingQueue.size() == 1){ 
       // this is only element in queue, i.e. queue was empty before, so invoke if any thread waiting for mails in queue. 
       lock.notify(); 
      } 
     } 
    } 

    public Mail pop() throws InterruptedException{ 
     synchronized (lock) { 
      while(backingQueue.isEmpty()){ 
       // no elements in queue, wait. 
       lock.wait(); 
      } 
      return backingQueue.removeFirst(); 
     } 
    } 

    public boolean removeBadMailsInstantly() { 
     synchronized (lock) { 
      boolean removed = false; 
      Iterator<Mail> iterator = backingQueue.iterator(); 

      while(iterator.hasNext()){ 
       Mail mail = iterator.next(); 
       if(mail.badMail){ 
        iterator.remove(); 
        removed = true; 
       } 
      } 

      return removed; 
     } 
    } 
} 

Die implementierte Warteschlangen werden threadsicher, ob Schub- oder Pop sein. Sie können die Warteschlange auch für weitere Operationen bearbeiten. Und es wird ermöglichen, Zugriff auf removeBadMailsInstantly Methode durch mehrere Threads (thread-safe). Und Sie werden auch Konzepte des Multithreading lernen.

+0

Wenn es viele Posts gibt, die alle diese Klasse und 'private final Object lock = new Object();' verwenden, werden sie sich gegenseitig blockieren oder wird jede Sperre irgendwie eindeutig sein? – Josh

+0

Downvoter, Grund für den Downvoting? – UDPLover

+0

@Josh Im Grunde müssen Sie eine Instanz dieser MailQueue erstellen und alle Threads diese Instanz verwenden lassen, so dass es nur eine Sperre gibt, wobei alle Threads dieselbe Sperre verwenden. – UDPLover