Как удалить элементы из очереди в Java с петлей

у меня есть такая структура данных:

почтовый ящик BlockingQueue = новый LinkedBlockingQueue ();

Я пытаюсь сделать это:

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

очевидно, что содержимое цикла мешает границам и запускается ошибка, поэтому я обычно делаю это:

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

но, к сожалению, BlockingQueue не имеют функции для получения или удаления элемента по индексу, поэтому я застрял. Есть идеи?

изменить - несколько очищения: Одна из моих целей-поддерживать тот же порядок, поэтому выскакивать из головы и возвращать ее в хвост нехорошо. Кроме того, хотя никакие другие потоки не удаляют почту из почтового ящика, они будут добавлять к ней, поэтому я не хочу быть в середине алгоритма удаления, чтобы кто-то отправил мне почту, а затем произошло исключение.

спасибо заранее!

3 ответов


вы можете поп poll и нажимаем offer все элементы в очереди, пока вы не сделаете полный цикл по очереди. Вот пример:

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();
}

обратите внимание, что этот подход будет работать только если этот код выполняется в одном потоке и нет никакой другой поток, который удаляет элементы из этой очереди.

Возможно, вам нужно проверить, действительно ли вы хотите опросить или взять элементы из BlockingQueue. Похожие для предложения и класть.

Подробнее:


другой менее ошибочный подход использует временную коллекцию, не обязательно параллельную, и хранит элементы, которые вам все еще нужны в очереди. Вот пример начала:

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);
}

Я просмотрел опубликованные решения, и я думаю, что нашел версию, которая служит моим целям. Что ты думаешь об этом?

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

Edit: новое решение, которое может быть без проблем. Что вы думаете?

while(true)
{
    boolean badNewRemains = false;

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

    if(!badNewRemains)
        break;
}

вы можете легко реализовать очередь для ваших нужд. И вам нужно будет, если API не имеет таких функций.

один такой:

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;
        }
    }
}

реализованная очередь будет потокобезопасной, будь то push или pop. Также вы можете редактировать очередь для дополнительных операций. И это позволит получить доступ removeBadMailsInstantly метод несколькими потоками (потокобезопасный). И вы также узнаете концепции многопоточности.