Java ArrayBlockingQueue和add vs put vs capacity

Java ArrayBlockingQueue和add vs put vs capacity,java,multithreading,data-structures,concurrency,queue,Java,Multithreading,Data Structures,Concurrency,Queue,从ArrayBlockingQueue的Javadoc: 加 公共布尔加法(E) 我始终将此声明(如果可以立即执行的话,部分)解释如下: 如果队列具有空闲容量,则插入将成功。如果没有空的空间,那么它就不会成功 但我的理解是错误的 在一个简单的例子中,我决定对20个元素(小队列)使用ArrayBlockingQueue,并让一个线程执行以下操作: queue.take() 另一个线程没有通过add方法向队列添加元素,尽管队列几乎为空 我也通过调试验证了它 有一次,我将queue.add(eleme

ArrayBlockingQueue
的Javadoc:

公共布尔加法(E)

我始终将此声明(如果可以立即执行的话,
部分)解释如下:

如果队列具有空闲容量,则插入将成功。如果没有空的空间,那么它就不会成功

但我的理解是错误的

在一个简单的例子中,我决定对20个元素(小队列)使用
ArrayBlockingQueue
,并让一个线程执行以下操作:

queue.take()

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

我也通过调试验证了它

有一次,我将
queue.add(element)
的调用替换为
queue.put(element)
该元素确实被添加到了队列中

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

除了容量之外,还有什么其他原因不能进行添加


更新:

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

}  
消费者:

public class ConnectionTreeUpdater extends Thread {  
  @Override
  public void run() {
    while(true){  
    try {  
    final ConnectionObject con = ConnectionListener.queueConnections.take();
如果使用
add
则不会引发异常,但元素不会添加到队列中

只是想一想:也许因为消费者在队列上“等待”,如果对于一些内部管理,元素不能被添加,它将不会被添加,并且不会抛出异常。可能是这样的

否则,我无法理解为什么没有例外,而
put
代码可以正常工作


put
add
的用法是否不同

其实很简单:

  • 如果队列未满,则两种方法均成功
  • 如果队列已满,则会失败并出现异常,而不会阻塞
我认为上面的文档非常清楚。如果您不同意,并且希望获得第二种意见,您可以检查
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();
    }
}

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

下面的测试用例显示,您使用的方法的行为与文档(您引用的文档)中的状态完全相同:

publicstaticvoidmain(字符串[]args){
最终阵列锁定队列myQueue=
新的ArrayBlockingQueue(10);
线程t1=新线程(新的可运行线程(){
公开募捐
{
int i=0;
while(true)
{
尝试
{
添加(i);
System.out.println(“添加到队列!值:”+
i+
“大小:”+myQueue.size());
i++;
}
捕获(例外e)
{
System.out.println(“add()引发异常,大小:”+
myQueue.size());
尝试
{
睡眠(1000);
}
捕获(中断异常例外)
{
Logger.getLogger(Main.class.getName()).log(Level.SEVERE,
零,ex);
}
}
}
}
});
线程t2=新线程(新可运行(){
公开募捐
{
while(true)
{
尝试
{
整数i=myQueue.take();
System.out.println(“从队列中删除了一个!值:”+
i+
“大小:”+myQueue.size());
睡眠(100);
}
捕获(中断异常例外)
{
Logger.getLogger(Main.class.getName()).log(Level.SEVERE,
零,ex);
}
}
}
});
t1.start();
t2.start();
}

我怀疑您捕获并忽略了由
add()
引发的异常,但没有看到您的代码,这只是猜测。您需要发布一个小的代码示例来演示您遇到的问题。实际上,add中没有例外。我刚刚做了
queue.add
,代码立即返回,没有添加元素,也没有exception@user384706:我们能否看到一个完整且可复制的测试用例来演示此行为(
add()
没有引发异常,但也没有将元素添加到队列)。不,它没有。它要么将其添加到队列中,要么抛出异常。这是仅有的两种可能的结果。@Brian:用一些代码更新了帖子
,如果您发现文档不明确,您可以通过查看源代码来验证这一点,因为实现细节和文档之间存在差异,所以总体上我对这个建议并不满意。如果文档不清楚(虽然我认为在本例中它很清楚),那么打开一个bug就更明智了(对于Java来说没有这么做,但是对于msdn来说不止一次了[好吧,win32 api文档很乱;-)]@Voo:我明白你的意思。然而,对于一个有意义的bug报告,必须有bug(或者有理由相信存在bug)。在这种情况下,文档和代码都非常清楚地说明了同一件事(在我看来)。我同意在这种情况下,文档已经足够清楚了(而且代码显然做了正确的事情)。如果文档真的不清楚,那么仅仅查看实现并假设它永远不会改变将是一个坏主意。为文档创建一个bug,看看这是否只是一个诚实的疏忽
public class ConnectionTreeUpdater extends Thread {  
  @Override
  public void run() {
    while(true){  
    try {  
    final ConnectionObject con = ConnectionListener.queueConnections.take();
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();
    }
}
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();

}