java - 求对ArrayBlockingQueue中一段源码的解释
问题描述
为什么take()方法在判断队列中元素个数是否为0的时候使用了while循环,而不是if;
我认为,如果notEmpty.await()方法既然苏醒返回了 ,那么此线程肯定拿到了lock。
而苏醒的原因也是因为put()方法放入了新的元素,而其他线程无法拿到锁,自然无法取走元素,那么此时对于拿到锁的线程来说count肯定不为0了,应该放心的执行 dequeue()获取元素就可以了。 不知道作者使用了while是何意呢?
问题解答
回答1:“notEmpty.await()方法既然苏醒返回了 ,那么此线程肯定拿到了 lock” 这句话是正确的。
假设你写的代码是:
if (count == 0) notEmpty.await();
可以明确的一点就是我们需要保证在 return dequeue() 之前需要满足的一个条件是 count != 0。我们假设 线程A 此时拿到了 lock,那么 线程A 的 notEmpty.await() 此时便会停止阻塞,准备向下执行 return dequeue()。但是假设在竞争激烈的条件下,线程A 拿到 lock 之后,准备执行下一条 JVM 指令的时候,线程B 此时抢占了 lock,然后继续向下执行 return dequeue(),刚好使得 count 变为了 0;而此时因为写的只是 if(count == 0),那么线程 A 在拿到 lock 之后,还是会继续向下执行 return dequeue(),从而导致了错误。
关于为什么wait()、await() 这样当条件不满足时就阻塞的方法一定要在 while 循环中使用,可以参考《Effective Java》第二版第 69 条(244 页)。
回答2:public ArrayBlockingQueue(int capacity, boolean fair) { if (capacity <= 0)throw new IllegalArgumentException(); this.items = new Object[capacity]; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); //notEmpty 就是这个锁的条件 notFull = lock.newCondition();}
所以在你这段代码里当前队列为空时(count==0),调用了notEmpty.await(),这段代码对锁是有影响的,实际上底层上已经释放了锁,只是这个方法保证了被唤醒时一定又能够拿回锁(当有元素放入队列会调用notEmpty.signal()进行唤醒),那为什么需要使用while呢?因为insert后lock.unlock,未必notEmpty.await()立即被唤醒,可能之前插入一个线程运行remove方法
相关文章:
1. javascript - vue 数据更新了。但是dom没有更新,,,,,如图2. java - 为什么要将Runnable接口的子类对象传递给Thread的构造函数?3. javascript - 读取页面源码,页面中所有的换行都被当成<br/>读取出来 了,,求解应该怎么让它被正确的解析4. docker api 开发的端口怎么获取?5. java基础,求解答。6. javascript - 关于一段 for 循环代码执行顺序的问题7. html5 - 百度Ueditor代码高亮和代码段滚动条冲突是怎么回事?8. debian - docker依赖的aufs-tools源码哪里可以找到啊?9. javascript - 静态页面引公共头尾文件,js怎么写吖?10. java - 3个dao的数据根据请求参数选择一个映射到一个url上,怎么写比较好?