2009-05-21 10 views
5

Câu hỏi này có liên quan với một trong những câu hỏi trước đây của tôi ..Chặn Queue - Cần thêm thông tin

Previous Post

Trong đó tính chất ngăn chặn được nhắc đến như một lợi thế.

Tôi đã cố gắng phát triển một số mã đơn giản để chứng minh tính chất chặn nhưng tôi gặp khó khăn. Tôi chỉ cố gắng tạo một kích thước BlockingQueue kích thước 4 và cố gắng thêm 5 phần tử và kết thúc bằng một số java.lang.IllegalStateException. Ai đó có thể chỉ cho tôi một ví dụ về mã để chặn bản chất của BlockingQueue không?


public static void main(String[] args) { 
    BlockingQueue<String> bq = new LinkedBlockingQueue<String>(4); 

    try { 
     bq.offer("A"); 
     bq.offer("B"); 
     bq.offer("C"); 
     bq.offer("D"); 
     bq.offer("E"); 

     System.out.println("1 = " + bq.take()); 
     System.out.println("2 = " + bq.take()); 
     System.out.println("3 = " + bq.take()); 
     System.out.println("4 = " + bq.take()); 
     System.out.println("5 = " + bq.take()); 
     System.out.println("6 = " + bq.take()); 
    } catch (Exception e) { 
     // TODO: handle exception 
     e.printStackTrace(); 
    } 
} 

tôi đã sử dụng đoạn mã này. Trong trường hợp này, tôi đang cố gắng đặt 5 phần tử vào hàng đợi với kích thước 4. Trong trường hợp này, 4 phần tử (A, B, C, D) sẽ được thêm vào hàng đợi. Sau đó, tôi gọi phương thức take() trong khi in. Không nên chèn "E" tự động vào hàng đợi khi tôi gọi System.out.println("1 = " + bq.take());? Bởi vì nó nhận được một khe miễn phí?

Trả lời

11

Were bạn thêm với add, offer, hoặc put? Tôi cho rằng bạn đang sử dụng add, vì nó là người duy nhất có thể ném IllegalStateException; nhưng nếu bạn đọc table, bạn sẽ thấy rằng nếu bạn muốn chặn ngữ nghĩa, bạn nên sử dụng put (và take để xóa).

Chỉnh sửa: Có một vài vấn đề với ví dụ của bạn.

Trước tiên tôi sẽ trả lời câu hỏi "Tại sao E không được chèn vào khi tôi gọi take() lần đầu tiên?" Câu trả lời là khi bạn gọi take(), bạn đã thử và không thành công để chèn E. Sau đó, không có gì để chèn khi không gian đã được giải phóng.

Bây giờ, nếu bạn thay đổi offer() thành put(), put("E") sẽ không bao giờ trở lại. Tại sao?Vì nó đang đợi một số chủ đề khác để xóa một phần tử khỏi hàng đợi. Hãy nhớ rằng, BlockingQueues được thiết kế cho nhiều chủ đề để truy cập. Chặn là vô ích (thực sự tồi tệ hơn vô ích) nếu bạn có một ứng dụng đơn luồng.

Dưới đây là một ví dụ cải thiện:

public static void main(String[] args) { 
    final BlockingQueue<String> bq = new LinkedBlockingQueue<String>(4); 

    Runnable producer = new Runnable() { 
     public void run() { 
      try { 
       bq.put("A"); 
       bq.put("B"); 
       bq.put("C"); 
       bq.put("D"); 
       bq.put("E"); 
      } catch (InterruptedException ex) { 
       Thread.currentThread().interrupt(); 
      } 
     } 
    }; 
    Runnable consumer = new Runnable() { 
     public void run() { 
      try { 
       System.out.println("1 = " + bq.take()); 
       System.out.println("2 = " + bq.take()); 
       System.out.println("3 = " + bq.take()); 
       System.out.println("4 = " + bq.take()); 
       System.out.println("5 = " + bq.take()); 
       System.out.println("6 = " + bq.take()); 
      } catch (InterruptedException ex) { 
       Thread.currentThread().interrupt(); 
      } 
     } 
    }; 
    new Thread(producer).start(); 
    new Thread(consumer).start(); 
} 

Bây giờ cuộc gọi put("E") sẽ thực sự thành công, vì nó bây giờ có thể chờ đợi cho đến khi thread tiêu dùng loại bỏ "A" từ hàng đợi. Cuối cùng take() sẽ vẫn chặn vô hạn vì không có phần tử thứ sáu cần xóa.

+0

Trước đây tôi đã sử dụng Thêm + Cuộc thăm dò ý kiến. Nhưng tại thời điểm này tôi đang cố gắng đặt + Hãy –

+0

Hmm .... Có điểm .. Thử nghiệm ngay bây giờ :) –

+0

Tôi nên chỉ định thời gian chờ cho PUT() như thế nào? –

2

mmyers đánh bại tôi với nó: P (+1)
nên là những gì bạn cần, chúc may mắn!

LƯU Ý: put() sẽ thất bại trong ví dụ của bạn vì put() sẽ chặn cho đến khi không gian khả dụng. Vì không gian không bao giờ có sẵn, chương trình không bao giờ tiếp tục thực hiện.

==== cũ câu trả lời ======

một BlockingQueue là một giao diện, bạn sẽ phải sử dụng một trong các lớp implementating.

"Blocking Nature" chỉ đơn giản nói rằng bạn có thể yêu cầu thứ gì đó từ hàng đợi của bạn, và nếu nó rỗng, thì nó nằm trong đó khối (chờ) cho đến khi thứ gì đó được thêm vào hàng đợi và tiếp tục xử lý.

ArrayBlockingQueue
DelayQueue
LinkedBlockingQueue
PriorityBlockingQueue
SynchronousQueue

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html

//your main collection 
LinkedBlockingQueue<Integer> lbq = new LinkedBlockingQueue<Integer>(); 

//Add your values 
lbq.put(100); 
lbq.put(200); 

//take() will actually remove the first value from the collection, 
//or block if no value exists yet. 
//you will either have to interrupt the blocking, 
//or insert something into the queue for the program execution to continue 

int currVal = 0; 
try { 
    currVal = lbq.take(); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} 

+0

Cảm ơn .. Tôi sử dụng "LinkedBlockingQueue" –

+0

tuyệt vời, đó là tất cả những gì bạn cần? Tôi đang làm một ví dụ ngay bây giờ nếu bạn vẫn muốn tôi đăng nó –

+0

Tốt hơn bạn nên đăng nó. Chỉ là một ví dụ ngắn :) –

1

Để trả lời cụ thể câu hỏi của bạn: Đề nghị là một cuộc gọi phiếu mua hàng không chặn, do đó, trong một phương thức duy nhất được gửi, cuộc gọi đến ('E') chỉ trả về false mà không sửa đổi toàn bộ hàng đợi. Nếu bạn sử dụng cuộc gọi chặn ('E'), nó sẽ ngủ cho đến khi không gian có sẵn. Vô hạn trong ví dụ đơn giản của bạn. Bạn sẽ cần phải có một thread riêng biệt đọc ra khỏi hàng đợi để tạo ra không gian cho việc đưa vào để hoàn thành.

+0

thay thế phiếu mua hàng bằng cách đặt nhưng không thành công. Tôi có cần phải sử dụng một thread riêng biệt cho PUT() các mục? –

+0

Trong câu trả lời của tôi, tôi nói: Bạn sẽ cần phải có một chủ đề riêng biệt đọc ra khỏi hàng đợi để tạo ra không gian cho việc đưa vào để hoàn thành. – lostlogic

+0

Có. Có điểm :) –

0

Hi biết thêm lớp này

/** 
* Inserts the specified element into this queue if it is possible to do 
* so immediately without violating capacity restrictions, returning 
* {@code true} upon success and throwing an 
* {@code IllegalStateException} if no space is currently available. 
* When using a capacity-restricted queue, it is generally preferable to 
* use {@link #offer(Object) offer}. 
* 
* @param e the element to add 
* @return {@code true} (as specified by {@link Collection#add}) 
* @throws IllegalStateException if the element cannot be added at this 
*   time due to capacity restrictions 
* @throws ClassCastException if the class of the specified element 
*   prevents it from being added to this queue 
* @throws NullPointerException if the specified element is null 
* @throws IllegalArgumentException if some property of the specified 
*   element prevents it from being added to this queue 
*/ 
boolean add(E e); 

/** 
* Inserts the specified element into this queue if it is possible to do 
* so immediately without violating capacity restrictions, returning 
* {@code true} upon success and {@code false} if no space is currently 
* available. When using a capacity-restricted queue, this method is 
* generally preferable to {@link #add}, which can fail to insert an 
* element only by throwing an exception. 
* 
* @param e the element to add 
* @return {@code true} if the element was added to this queue, else 
*   {@code false} 
* @throws ClassCastException if the class of the specified element 
*   prevents it from being added to this queue 
* @throws NullPointerException if the specified element is null 
* @throws IllegalArgumentException if some property of the specified 
*   element prevents it from being added to this queue 
*/ 
boolean offer(E e); 

/** 
* Inserts the specified element into this queue, waiting if necessary 
* for space to become available. 
* 
* @param e the element to add 
* @throws InterruptedException if interrupted while waiting 
* @throws ClassCastException if the class of the specified element 
*   prevents it from being added to this queue 
* @throws NullPointerException if the specified element is null 
* @throws IllegalArgumentException if some property of the specified 
*   element prevents it from being added to this queue 
*/ 
void put(E e) throws InterruptedException; 

/** 
* Inserts the specified element into this queue, waiting up to the 
* specified wait time if necessary for space to become available. 
* 
* @param e the element to add 
* @param timeout how long to wait before giving up, in units of 
*  {@code unit} 
* @param unit a {@code TimeUnit} determining how to interpret the 
*  {@code timeout} parameter 
* @return {@code true} if successful, or {@code false} if 
*   the specified waiting time elapses before space is available 
* @throws InterruptedException if interrupted while waiting 
* @throws ClassCastException if the class of the specified element 
*   prevents it from being added to this queue 
* @throws NullPointerException if the specified element is null 
* @throws IllegalArgumentException if some property of the specified 
*   element prevents it from being added to this queue 
*/ 
boolean offer(E e, long timeout, TimeUnit unit) 
    throws InterruptedException; 

/** 
* Retrieves and removes the head of this queue, waiting if necessary 
* until an element becomes available. 
* 
* @return the head of this queue 
* @throws InterruptedException if interrupted while waiting 
*/ 
E take() throws InterruptedException; 

/** 
* Retrieves and removes the head of this queue, waiting up to the 
* specified wait time if necessary for an element to become available. 
* 
* @param timeout how long to wait before giving up, in units of 
*  {@code unit} 
* @param unit a {@code TimeUnit} determining how to interpret the 
*  {@code timeout} parameter 
* @return the head of this queue, or {@code null} if the 
*   specified waiting time elapses before an element is available 
* @throws InterruptedException if interrupted while waiting 
*/ 
E poll(long timeout, TimeUnit unit) 
    throws InterruptedException;