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

我有这样的数据结构:

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没有通过索引获取或删除元素的功能,所以我被卡住了。 有任何想法吗?

编辑 - 几个澄清:我的目标之一是保持相同的排序,所以从头部弹出并将其放回到尾部是不好的。 此外,虽然没有其他线程会从邮箱中删除邮件,但它们会添加到邮箱中,因此我不希望处于删除算法的中间,有人向我发送邮件,然后发生异常。

提前致谢!


您可以通过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中获取元素。 类似的报价和投入。

更多信息:

  • Java BlockingQueue take()vs poll()
  • LinkedBlockingQueue与优惠

  • 另一个少花钱的方法是使用临时集合,不一定是并发的,并将你仍然需要的元素存储在队列中。 这是一个开球的例子:

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

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

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

    实现的队列将是线程安全的,无论是推送还是流行。 您也可以编辑队列以获取更多操作。 它将允许通过多线程访问removeBadMailsInstantly方法(线程安全)。 你还将学习多线程的概念。

    链接地址: http://www.djcxy.com/p/23191.html

    上一篇: How to remove elements from a queue in Java with a loop

    下一篇: Error: Could not symlink bin/dvipdf when installing Octave