ArrayBlockingQueue 以及添加、放置和容量

发布于 2024-12-09 02:38:41 字数 1887 浏览 0 评论 0原文

来自 ArrayBlockingQueue ArrayBlockingQueue

添加

公共布尔添加(E e)

如果可能,将指定元素插入到此队列的尾部 
立即执行此操作而不超出队列的容量,返回 true 
成功后,如果队列已满,则抛出 IllegalStateException。

我总是解释这个语句(如果可以立即这样做部分)如下:

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

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

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

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

}  

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

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

而消费者:

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

如果我使用 add ,则不会引发异常,但元素不会添加到队列中。

只是一个想法:也许由于消费者正在队列上“等待”,如果对于某些内部事务处理无法添加该元素,则该元素将不会被添加,并且不会引发异常。可能是这种情况吗?

否则我无法理解为什么没有异常并且使用 put 代码可以工作。

putadd 的用法是否不同?

From Javadoc of 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'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 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 ArrayBlockingQueue for e.g. 20 elements (small queue) and having one thread doing:

queue.take()

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

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.

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

}  

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

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 put the code works.

Are put and add meant to be used differently?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

裂开嘴轻声笑有多痛 2024-12-16 02:38:41

其实很简单:

  • 如果队列未满,两种方法都会成功;如果队列未满,则两种方法都会成功。
  • 如果队列已满,添加() 因异常而失败,而 put() 块。

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

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.

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:

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();
    }
}
九厘米的零° 2024-12-16 02:38:41

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

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

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

}

One of the more important parts of debugging a problem is writing a test case to 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();

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文