ArrayBlockingQueue and adding vs put vs capacity

From the Javadoc ArrayBlockingQueue ArrayBlockingQueue :

add

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 capacity, returning true upon success and throwing an IllegalStateException if this queue is full. 

I have always interpreted this statement (part of if it is possible to do so immediattely ) as follows:

If the queue has free capacity, then the insert will succeed. If there is no empty space, then this will not succeed.

But my understanding here was not so.

In the simple case, when I decided to use ArrayBlockingQueue , for example. 20 elements (small queue) and one thread:

queue.take()

another thread did not add the item to the queue using the add method, although the queue was almost empty.

I also checked this with debugging.

As soon as I replaced the call to queue.add(element) with queue.put(element) , the element was indeed added to the queue.

So, what is different from the methods in this?

For what other reason (besides capacity) can this addition happen?


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 is just a holder for String values.

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

And the consumer:

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

If I use add , an exception is not thrown, but the item is not added to the queue.

Just a thought: it’s possible, since the consumer is β€œwaiting” in line, if for some internal homework an element cannot be added, it will not be added, and no exception will be thrown. Maybe so.

Otherwise, I can’t understand why there is no exception, and the code works with put .

Are put and add differently?

+8
java multithreading concurrency data-structures queue
source share
2 answers

It is pretty simple:

  • If the queue is not full, both methods succeed;
  • If the queue is full, add() fails with an exception, while put() blocks.

I think the documentation is pretty clear above. If you disagree and want a second opinion, you can study the source code for 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(); } } 
+14
source share

One of the most important parts of debugging a problem is to write a test case to make sure that what you think is happening is actually happening. This either proves or disproves your theory.

The following test case shows that the methods you use behave exactly the same as the documentation (which you specify):

 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(); } 
+2
source share

All Articles