《java.util.concurrent 包源码阅读》06 ArrayBlockingQueue
对于BlockingQueue的具体实现,主要关注的有两点:线程安全的实现和阻塞操作的实现。所以分析ArrayBlockingQueue也是基于这两点。
对于线程安全来说,所有的添加元素的方法和拿走元素的方法都会涉及到,我们通过分析offer方法和poll()方法就能看出线程安全是如何实现的。
首先来看offer方法
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
insert(e);
return true;
}
} finally {
lock.unlock();
}
}
通过代码可以看出是通过采用Lock的方式来获取锁,然后再进行插入操作,最后再释放锁。
因此对于poll方法来说实现的方法肯定也是大同小异
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : extract();
} finally {
lock.unlock();
}
}
说过了线程安全的实现,接下来说说阻塞是如何实现的。如果各位知道Object的wait/notify的话就很好理解了。这里涉及到一个接口叫java.util.concurrent.locks.Condition。
Condition拥有类似的操作:await/signal。Condition和一个Lock相关,由Lock的newCondition来创建。只有当前线程获取了这把锁,才能调用Condition的await方法来等待通知,否则会抛出异常。
下面来看看put方法就会明白如何使用一个Condition了
notFull = lock.newCondition();
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
insert(e);
} finally {
lock.unlock();
}
}
实现阻塞的关键就是就是这个notFull的Condition,当队列已满,await方法会阻塞当前线程,并且释放Lock,等待其他线程调用notFull的signal来唤醒这个阻塞的线程。那么这个操作必然会在拿走元素的操作中出现,这样一旦有元素被拿走,阻塞的线程就会被唤醒。
这里有个问题,发出signal的线程肯定拥有这把锁的,因此await方法所在的线程肯定是拿不到这把锁的,await方法不能立刻返回,需要尝试获取锁直到拥有了锁才可以从await方法中返回。
这就是阻塞的实现原理,也是所谓的线程同步。
同样对于take方法会有一个notEmpty的Condition。
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return extract();
} finally {
lock.unlock();
}
}
需要注意的是这里返回队列长度的时候也是需要锁的
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return extract();
} finally {
lock.unlock();
}
}
ArrayBlockingQueue的实现相对简单,只需要一把锁就可以搞定,下一篇关于LinkedBlockingQueue则会复杂不少,需要用到两把锁。
《java.util.concurrent 包源码阅读》06 ArrayBlockingQueue的更多相关文章
- 《java.util.concurrent 包源码阅读》 结束语
<java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...
- 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包
Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...
- 《java.util.concurrent 包源码阅读》04 ConcurrentMap
Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...
- 《java.util.concurrent 包源码阅读》17 信号量 Semaphore
学过操作系统的朋友都知道信号量,在java.util.concurrent包中也有一个关于信号量的实现:Semaphore. 从代码实现的角度来说,信号量与锁很类似,可以看成是一个有限的共享锁,即只能 ...
- 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇
concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...
- 《java.util.concurrent 包源码阅读》05 BlockingQueue
想必大家都很熟悉生产者-消费者队列,生产者负责添加元素到队列,如果队列已满则会进入阻塞状态直到有消费者拿走元素.相反,消费者负责从队列中拿走元素,如果队列为空则会进入阻塞状态直到有生产者添加元素到队列 ...
- 《java.util.concurrent 包源码阅读》10 线程池系列之AbstractExecutorService
AbstractExecutorService对ExecutorService的执行任务类型的方法提供了一个默认实现.这些方法包括submit,invokeAny和InvokeAll. 注意的是来自E ...
- 《java.util.concurrent 包源码阅读》22 Fork/Join框架的初体验
JDK7引入了Fork/Join框架,所谓Fork/Join框架,个人解释:Fork分解任务成独立的子任务,用多线程去执行这些子任务,Join合并子任务的结果.这样就能使用多线程的方式来执行一个任务. ...
随机推荐
- sql server 2008 18456错误
来自:http://blog.csdn.net/qishuangquan/article/details/6024767 百度搜18456错误几乎只能搜到一篇文章,并不是说结果条数,而是所有的文章都是 ...
- win10 UWP RSS阅读器
RSS简易信息聚合(也叫聚合内容)是一种RSS基于XML标准,在互联网上被广泛采用的内容包装和投递协议.RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是使 ...
- UVa1605,Building for UN
我比较好奇的是uva后台是怎么测这题的 没什么可说的,那些不想敲但还是想直接交这题的直接copy过去吧 #include <iostream> #include <cstring&g ...
- LINUX 笔记-find 命令常用用法
命令格式: find path -option [-print] [-exec -ok] -print:find 命令将匹配的文件输出到标准输出 -exec:find 命令对匹配的文件执行该参数所给出 ...
- Python数据库查询之组合条件查询-F&Q查询
F查询(取字段的值) 关于查询我们知道有filter( ) ,values( ) , get( ) ,exclude( ) ,如果是聚合分组,还会用到aggregate和annotate,甚至还有万能 ...
- 使用gitbook
前面的话 gitbook功能强大,可以自动实现搜索及翻页等功能,上手容易,用markdown书写即可,且可以自动生成响应式网站.本文将详细介绍如何使用gitbook 安装 1.使用npm全局安装git ...
- Best Coder #86 1001 Price List(大水题)
Price List Accepts: 880 Submissions: 2184 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 26214 ...
- Can you solve this equation?
Can you solve this equation? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav ...
- 值得认真学习的6 个 JavaScript 框架
JavaScript JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本 ...
- 三目运算的使用&bytes类型转str类型
一.三目运算的使用 就像c语言中有三目运算符一样,python中也有三目运算符,废话不多说直接上代码 a=3 c=4 b=a if a>c else c print(b) 意思就和 if a&g ...