2011-10-09 41 views
8

Từ Javadoc của ArrayBlockingQueueArrayBlockingQueue:ArrayBlockingQueue và thêm vs đặt vs công suất

thêm

public boolean add (E e)

Inserts the specified element at the tail of this queue if it is possible 
to do so immediately without exceeding the queue's capacity, returning true 
upon success and throwing an IllegalStateException if this queue is full. 

Tôi luôn interpretted tuyên bố này (một phần if it is possible to do so immediattely) như sau:

Nếu hàng đợi có dung lượng miễn phí, khi đó chèn sẽ thành công. Nếu không có không gian trống thì nó sẽ không thành công.

Nhưng sự hiểu biết của tôi sai ở đây.

Trong trường hợp đơn giản, tôi quyết định sử dụng số ArrayBlockingQueue cho ví dụ: 20 yếu tố (hàng đợi nhỏ) và có một thread thực hiện:

queue.take()

thread khác không thêm một yếu tố để xếp hàng thông qua phương thức add mặc dù hàng đợi đã gần như trống rỗng.

Tôi đã xác minh nó cũng thông qua gỡ lỗi.

Khi tôi đã thay thế cuộc gọi queue.add(element) thành queue.put(element) yếu tố này thực sự đã được thêm vào hàng đợi.

Vậy các phương pháp này khác nhau như thế nào?

Vì lý do nào khác (ngoài năng lực), việc bổ sung có thể xảy ra không?


UPDATE:

public class ConnectionListener implements Observer { 

    public static BlockingQueue<ConnectionObject> queueConnections = new ArrayBlockingQueue<ConnectionObject>(10); 

    @Override 
    public void update(Observable arg0, Object arg1) { 
     ConnectionObject con = ((ConnectionObject)arg1); 
     queueConnections.add(con); 
    } 

} 

ConnectionObject chỉ là một người giữ cho các giá trị String.

public class ConnectionObject { 
    private String user; 
    private String ip; 
    //etc 
} 

Và người tiêu dùng:

public class ConnectionTreeUpdater extends Thread { 
    @Override 
    public void run() { 
    while(true){ 
    try { 
    final ConnectionObject con = ConnectionListener.queueConnections.take(); 

Nếu tôi sử dụng add không phải ngoại lệ được ném nhưng yếu tố không được thêm vào hàng đợi.

Chỉ cần suy nghĩ: có lẽ vì người tiêu dùng đang "chờ" trên hàng đợi, nếu đối với một số dịch vụ vệ sinh nội bộ thì không thể thêm phần tử đó vào nó và không có ngoại lệ nào được ném.

Nếu không, tôi không thể hiểu tại sao không có ngoại lệ và với mã put hoạt động.

Có phải putadd có nghĩa là được sử dụng khác nhau?

+0

tôi nghi ngờ bạn bị bắt và bỏ qua ngoại lệ được ném bởi 'thêm()' nhưng không thấy mã của bạn chỉ là một phỏng đoán. Bạn cần đăng một ví dụ mã nhỏ thể hiện sự cố bạn đang gặp phải. –

+0

Trên thực tế không có ngoại lệ trong phần bổ sung. Tôi chỉ làm 'queue.add' và mã trả về immediatelly mà không thêm phần tử và không có ngoại lệ – Cratylus

+0

@ user384706: Chúng ta có thể xem một trường hợp kiểm tra đầy đủ và có thể tái tạo để chứng minh hành vi này (' add() 'không ném ngoại lệ không thêm phần tử vào hàng đợi). – NPE

Trả lời

14

Nó khá đơn giản thực sự:

  • nếu hàng đợi là không đầy đủ, cả hai phương pháp thành công;
  • nếu hàng đợi đầy, add() không thành công với ngoại lệ trong khi put() khối.

Tôi nghĩ tài liệu này khá rõ ràng ở trên. Nếu bạn không đồng ý, và muốn có một ý kiến ​​thứ hai, bạn có thể kiểm tra mã nguồn cho ArrayBlockingQueue:

public boolean add(E e) { 
    if (offer(e)) 
     return true; 
    else 
     throw new IllegalStateException("Queue full"); 
} 

public boolean offer(E e) { 
    if (e == null) throw new NullPointerException(); 
    final ReentrantLock lock = this.lock; 
    lock.lock(); 
    try { 
     if (count == items.length) 
      return false; 
     else { 
      insert(e); 
      return true; 
     } 
    } finally { 
     lock.unlock(); 
    } 
} 

public void put(E e) throws InterruptedException { 
    if (e == null) throw new NullPointerException(); 
    final E[] items = this.items; 
    final ReentrantLock lock = this.lock; 
    lock.lockInterruptibly(); 
    try { 
     try { 
      while (count == items.length) 
       notFull.await(); 
     } catch (InterruptedException ie) { 
      notFull.signal(); // propagate to non-interrupted thread 
      throw ie; 
     } 
     insert(e); 
    } finally { 
     lock.unlock(); 
    } 
} 
+0

'Nếu bạn thấy tài liệu mơ hồ, bạn có thể xác minh điều này bằng cách xem source code' - Vâng, có một sự khác biệt giữa một chi tiết thực hiện và tài liệu, vì vậy tôi không thực sự hài lòng với lời khuyên đó nói chung. Nếu tài liệu không rõ ràng (mặc dù tôi nghĩ rằng nó khá rõ ràng trong trường hợp này), mở một lỗi là hợp lý hơn tôi nghĩ (đã không làm điều đó cho Java, nhưng nhiều hơn một lần cho msdn [cũng win32 api doc là một mess mặc dù ;-)]) – Voo

+0

@Voo: Tôi thấy quan điểm của bạn. Tuy nhiên, đối với một báo cáo lỗi có ý nghĩa thì phải có một lỗi (hoặc một niềm tin hợp lý rằng có một lỗi). Trong trường hợp này cả hai tài liệu và mã rất rõ ràng cùng một điều (đôi mắt của tôi anyway). – NPE

+0

Tôi đồng ý rằng trong trường hợp này tài liệu là đủ rõ ràng (tốt và mã rõ ràng là đúng điềuTM). Chỉ cần nếu tài liệu thực sự không rõ ràng, chỉ cần nhìn vào việc thực hiện và giả định rằng nó không bao giờ có thể thay đổi sẽ là một ý tưởng tồi. Tạo một lỗi cho tài liệu để xem liệu đó có phải là một sự giám sát trung thực hay không được xác định vì lý do chính đáng là imo quá trình hành động tốt hơn (đầu tiên là googling xung quanh rõ ràng;)) – Voo

2

Một trong những phần quan trọng hơn của gỡ một vấn đề được viết một trường hợp thử nghiệm để đảm bảo những gì bạn nghĩ đang xảy ra thực sự xảy ra. Điều này chứng minh hoặc bác bỏ lý thuyết của bạn.

Các trường hợp thử nghiệm dưới đây cho thấy những phương pháp bạn đang sử dụng cư xử chính xác như các tài liệu (mà bạn trích dẫn) khẳng định:

public static void main(String[] args) { 

    final ArrayBlockingQueue<Integer> myQueue = 
      new ArrayBlockingQueue<Integer>(10); 


    Thread t1 = new Thread(new Runnable() { 

     public void run() 
     { 
      int i = 0; 
      while (true) 
      { 
       try 
       { 
        myQueue.add(i); 
        System.out.println("Added to queue! value: " + 
             i + 
             " size: " + myQueue.size()); 
        i++; 
       } 
       catch (Exception e) 
       { 
        System.out.println("add() threw exception, size: " + 
             myQueue.size()); 
        try 
        { 
         Thread.sleep(1000); 
        } 
        catch (InterruptedException ex) 
        { 
         Logger.getLogger(Main.class.getName()).log(Level.SEVERE, 
                    null, ex); 
        } 
       } 
      } 
     } 

    }); 

    Thread t2 = new Thread(new Runnable() { 

     public void run() 
     { 
      while (true) 
      { 
       try 
       { 
        Integer i = myQueue.take(); 
        System.out.println("Took a off the queue! value: " + 
             i + 
             " size: " + myQueue.size()); 
        Thread.sleep(100); 
       } 
       catch (InterruptedException ex) 
       { 
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, 
                   null, ex); 
       } 
      } 
     } 
    }); 

    t1.start(); 
    t2.start(); 

}