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