如何使用循环从Java中删除队列中的元素

时间:2014-10-21 04:44:22

标签: java loops blockingqueue

我有这样的数据结构:

  

BlockingQueue mailbox = new 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 个答案:

答案 0 :(得分:3)

您可以pyouro̶p̶poll和p̶u̶s̶h̶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);
}

答案 1 :(得分:0)

我查看了发布的解决方案,我认为我找到了一个符合我目的的版本。你觉得这个怎么样?

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

编辑:一个可能没有问题的新解决方案。你们的想法是什么?

while(true)
{
    boolean badNewRemains = false;

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

    if(!badNewRemains)
        break;
}

答案 2 :(得分:0)

您可以根据需要轻松实施队列。如果提供的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方法(线程安全)。您还将学习多线程的概念。