2014-10-21 15 views
7

Tôi có một cấu trúc dữ liệu như thế này:Làm thế nào để loại bỏ các yếu tố từ một hàng đợi trong Java với một vòng lặp

mailbox BlockingQueue = new LinkedBlockingQueue();

Tôi đang cố gắng để làm điều này:

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

Rõ ràng các nội dung của vòng can thiệp với các giới hạn và một lỗi được kích hoạt, vì vậy tôi thường làm điều này:

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

Nhưng đáng buồn là BlockingQueue không có chức năng lấy hoặc xóa một phần tử theo chỉ mục, vì vậy tôi bị kẹt. Ý tưởng nào?

Chỉnh sửa - Một số giải thích rõ ràng: Một trong những mục tiêu của tôi là duy trì cùng một thứ tự như vậy xuất hiện từ đầu và đưa nó trở lại vào đuôi là không tốt. Ngoài ra, mặc dù không có chủ đề nào khác sẽ xóa thư khỏi hộp thư, chúng sẽ thêm vào thư, vì vậy tôi không muốn ở giữa thuật toán xóa, nhờ ai đó gửi thư cho tôi và sau đó có ngoại lệ.

Cảm ơn trước!

+0

kiểm tra câu trả lời tôi đã đăng .. – UDPLover

Trả lời

3

Bạn có thể p̶o̶p̶ poll và p̶u̶s̶h̶ offer tất cả các phần tử trong hàng đợi cho đến khi bạn tạo vòng lặp hoàn chỉnh trên hàng đợi của mình. Dưới đây là ví dụ:

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

Lưu ý rằng phương pháp này sẽ chỉ hoạt động nếu mã này được thực thi trong một chuỗi và không có chuỗi nào khác xóa mục khỏi hàng đợi này.

Có thể bạn cần kiểm tra xem bạn có thực sự muốn thăm dò ý kiến ​​hoặc lấy các yếu tố từ BlockingQueue hay không. Tương tự cho cung cấp và đặt. Thông tin

thêm:


Một cách tiếp cận ít lỗi đang sử dụng một bộ sưu tập tạm thời, không nhất thiết đồng thời, và lưu trữ các yếu tố bạn vẫn cần trong xếp hàng. Dưới đây là ví dụ về khởi động:

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 * cố định *. Tuy nhiên, OP không thông báo cho chúng tôi nếu các chủ đề khác cũng xóa các mục khỏi hàng đợi. –

+0

@ScaryWombat tốt, tôi không đọc bất kỳ câu hỏi nào khác, vì vậy tôi thiếu ngữ cảnh này. –

+0

Có lẽ tôi đang thiếu điểm của bạn, nhưng không 'peek' trả về null nếu hàng đợi trống (không chặn)? Trong phiên bản trước của bạn, nếu hàng đợi trống trước khi vào vòng lặp của bạn, nó sẽ ném một NPE. –

0

Tôi đã xem xét các giải pháp được đăng và tôi nghĩ rằng tôi đã tìm thấy một phiên bản phục vụ mục đích của mình. Bạn nghĩ gì về cái này?

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

Chỉnh sửa: Giải pháp mới có thể không có sự cố. Các bạn nghĩ sao?

while(true) 
{ 
    boolean badNewRemains = false; 

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

    if(!badNewRemains) 
     break; 
} 
+0

Kích thước của hàng đợi có thể thay đổi vì các chủ đề khác đang thêm nhiều thư vào hàng đợi. Hãy cẩn thận về điều này. –

+0

Vâng, bây giờ tôi thấy rằng các yếu tố có thể được ra lệnh nếu dữ liệu mới đến ở giữa. Tôi đã thử một lần nữa ở trên. – Josh

0

Bạn có thể dễ dàng triển khai hàng đợi cho nhu cầu của mình. Và bạn sẽ cần, nếu API được cung cấp không có các tính năng như vậy.

Một như:

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

Hàng đợi thực hiện sẽ được thread-safe, cho dù push hoặc pop. Ngoài ra, bạn có thể chỉnh sửa hàng đợi cho nhiều hoạt động hơn. Và nó sẽ cho phép truy cập phương thức removeBadMailsInstantly theo nhiều luồng (thread-safe). Và bạn cũng sẽ học các khái niệm về đa luồng.

+0

Nếu có nhiều mẩu thư đều sử dụng lớp này và 'Object lock cuối cùng riêng tư = new Object();', chúng sẽ chặn lẫn nhau hay mỗi khóa bằng cách nào đó sẽ là duy nhất? – Josh

+0

Downvoter, lý do để downvoting? – UDPLover

+0

@Josh Về cơ bản bạn phải tạo một thể hiện của MailQueue này, và để cho tất cả các chủ đề sử dụng cá thể này, vì vậy sẽ chỉ có một khóa, tất cả các luồng sử dụng cùng một khóa. – UDPLover

Các vấn đề liên quan