Как удалить элементы из очереди в 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
метод несколькими потоками (потокобезопасный). И вы также узнаете концепции многопоточности.