java ArrayBlockingQueue 和添加 vs 放置 vs 容量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7706666/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 21:04:11  来源:igfitidea点击:

ArrayBlockingQueue and add vs put vs capacity

javamultithreadingdata-structuresconcurrencyqueue

提问by Cratylus

From Javadoc of ArrayBlockingQueueArrayBlockingQueue:

来自ArrayBlockingQueueArrayBlockingQueue 的Javadoc :

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

添加

公共布尔添加(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.

I always interpretted this statement (the part if it is possible to do so immediattely) as follows:

我总是将这句话(部分if it is possible to do so immediattely)解释如下:

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

如果队列有空闲容量,则插入将成功。如果没有空白空间,则不会成功。

But my understanding was wrong here.

但我的理解在这里是错误的。

In a simple case that I decided to use an ArrayBlockingQueuefor e.g. 20 elements (small queue) and having one thread doing:

在一个简单的情况下,我决定使用ArrayBlockingQueuefor 例如 20 个元素(小队列)并让一个线程执行:

queue.take()

queue.take()

the other thread did not add an element to the queue via the addmethod despite the queue was almost empty.

add尽管队列几乎为空,但另一个线程没有通过该方法向队列添加元素。

I verified it also via debugging.

我也通过调试验证了它。

Once I replaced the call of queue.add(element)to queue.put(element)the element was indeed added to the queue.

一旦我取代的号召queue.add(element),以queue.put(element)元素确实加入到队列中。

So what is so different in these to methods?

那么这些方法有什么不同呢?

For what other reason (besides capacity) could the addition not 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);
  }

}  

ConnectionObjectis just a holder for String values.

ConnectionObject只是字符串值的持有者。

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 addno exception is thrown but element does not get added to the queue.

如果我使用add没有异常抛出但元素不会被添加到队列中。

Just a thought: perhaps since the consumer is "waiting" on the queue, if for some internal housekeeping the element can not be added it will not be added and no exception is thrown.Could that be the case.

只是一个想法:也许因为消费者在队列中“等待”,如果对于某些内部整理,元素无法添加,则不会添加元素,也不会抛出异常。可能是这种情况。

Otherwise I can not understand why there is no exception and with putthe code works.

否则我无法理解为什么没有例外并且put代码有效。

Are putand addmeant to be used differently?

putadd意味着要使用不同?

回答by NPE

It's quite simple really:

其实很简单:

  • if the queue is not full, both methods succeed;
  • if the queue is full, add()fails with an exception whereas put()blocks.
  • 如果队列未满,则两种方法都成功;
  • 如果队列已满,add()则会因异常而失败而put()阻塞。

I think the documentation is pretty clear on the above. If you don't agree, and would like a second opinion, you could examine the source code for ArrayBlockingQueue:

我认为上面的文档非常清楚。如果您不同意,并希望获得第二意见,您可以检查以下源代码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();
    }
}

回答by Brian Roach

One of the more important parts of debugging a problem is writing a test caseto make sure what you think is happening is indeed happening. This either proves or disproves your theory.

调试问题的一个更重要的部分是编写一个测试用例,以确保您认为正在发生的事情确实正在发生。这要么证明要么反驳你的理论。

The test case below shows that the methods you are using behave exactly as the documentation (which you quote) states:

下面的测试用例显示您使用的方法的行为与文档(您引用的)完全一致:

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

}