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
ArrayBlockingQueue and add vs put vs capacity
提问by Cratylus
From Javadoc of ArrayBlockingQueue
ArrayBlockingQueue:
来自ArrayBlockingQueue
ArrayBlockingQueue 的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 ArrayBlockingQueue
for e.g. 20 elements (small queue) and having one thread doing:
在一个简单的情况下,我决定使用ArrayBlockingQueue
for 例如 20 个元素(小队列)并让一个线程执行:
queue.take()
queue.take()
the other thread did not add an element to the queue via the add
method 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);
}
}
ConnectionObject
is 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 add
no 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 put
the code works.
否则我无法理解为什么没有例外并且put
代码有效。
Are put
and add
meant to be used differently?
是put
和add
意味着要使用不同?
回答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 whereasput()
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
:
我认为上面的文档非常清楚。如果您不同意,并希望获得第二意见,您可以检查以下源代码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();
}