Java源码之阻塞队列

⑴背景

阻塞队列常用于生产者消费者场景,生产者是向队列里添加元素的线程,消费者是向队列里取出元素的线程。阻塞队列的角色是供生产者存放元素,消费者取出元素的容器。

 

⑵阻塞队列

阻塞队列是一个支持两个附加操作的队列。(支持阻塞插入和移除方法)

①阻塞插入:当队列满时,队列会阻塞插入元素的线程,直到队列不满。

②阻塞移除:当队列空时,获取元素的线程会等待队列变为空。

 

 1  /** The queued items */
 2     final Object[] items;
 3 
 4     /** items index for next take, poll, peek or remove */
 5     int takeIndex;
 6 
 7     /** items index for next put, offer, or add */
 8     int putIndex;
 9 
10     /** Number of elements in the queue */
11     int count;
12 
13     /*
14      * Concurrency control uses the classic two-condition algorithm
15      * found in any textbook.
16      */
17 
18     /** Main lock guarding all access */
19     final ReentrantLock lock;
20 
21     /** Condition for waiting takes */
22     private final Condition notEmpty;
23 
24     /** Condition for waiting puts */
25     private final Condition notFull;

 

 1 /**
 2      * Creates an {@code ArrayBlockingQueue} with the given (fixed)
 3      * capacity and the specified access policy.
 4      *
 5      * @param capacity the capacity of this queue
 6      * @param fair if {@code true} then queue accesses for threads blocked
 7      *        on insertion or removal, are processed in FIFO order;
 8      *        if {@code false} the access order is unspecified.
 9      * @throws IllegalArgumentException if {@code capacity < 1}
10      */
11     public ArrayBlockingQueue(int capacity, boolean fair) {
//当队列容量小于等于0,会抛异常。当队列满时再继续插入,也会抛该异常
12 if (capacity <= 0) 13 throw new IllegalArgumentException();
//创建容量数组
14 this.items = new Object[capacity];
//创建可重入锁与阻塞条件
15 lock = new ReentrantLock(fair); 16 notEmpty = lock.newCondition(); 17 notFull = lock.newCondition(); 18 }
 1 /**
 2      * Inserts the specified element at the tail of this queue, waiting
 3      * for space to become available if the queue is full.
 4      *
 5      * @throws InterruptedException {@inheritDoc}
 6      * @throws NullPointerException {@inheritDoc}
 7      */
 8     public void put(E e) throws InterruptedException {
 9         checkNotNull(e);
10         final ReentrantLock lock = this.lock;
//lockInterruptibly()允许在等待时由其他线程的Thread.interrupt()方法来中断等待线程而直接返回,这时是不用获取锁的,而会抛出一个InterruptException。
//而ReentrantLock.lock()方法则不允许Thread.interrupt()中断,即使检测到了Thread.interruptted一样会继续尝试获取锁,失败则继续休眠。只是在最后获取锁成功之后在把当前线程置为interrupted状态。
11 lock.lockInterruptibly(); 12 try {
//当队列满时,阻塞插入队列的线程
13 while (count == items.length) 14 notFull.await();
//对列不满就入队列
15 enqueue(e); 16 } finally {
//最后必须释放锁资源
17 lock.unlock(); 18 } 19 }
 1 public E take() throws InterruptedException {
 2         final ReentrantLock lock = this.lock;
//加锁保证只有一个线程进入take方法
3 lock.lockInterruptibly(); 4 try {
//当队列为空时,阻塞取出元素的线程
5 while (count == 0) 6 notEmpty.await();
//当队列队列非空时,允许元素加入队列
7 return dequeue(); 8 } finally { 9 lock.unlock(); 10 } 11 }

 

 1 /**
 2      * Inserts element at current put position, advances, and signals.
 3      * Call only when holding lock.
 4      */
 5     private void enqueue(E x) {
 6         // assert lock.getHoldCount() == 1;
 7         // assert items[putIndex] == null;
 8         final Object[] items = this.items;  //确保所有元素只放进同一个数组中
 9         items[putIndex] = x;  
10         if (++putIndex == items.length)  //当索引等于数组最大值时,索引置0
11             putIndex = 0;
12         count++;
13         notEmpty.signal();  //使用条件对象notEmpty通知,当调用take,poll,remove时,线程被阻塞,对列为空,当调用enqueue时,队列不为空了,使用signal函数进行通知
14     }

 

 1 /**
 2      * Extracts element at current take position, advances, and signals.
 3      * Call only when holding lock.
 4      */
 5     private E dequeue() {
 6         // assert lock.getHoldCount() == 1;
 7         // assert items[takeIndex] != null;
 8         final Object[] items = this.items;
 9         @SuppressWarnings("unchecked")
10         E x = (E) items[takeIndex];
11         items[takeIndex] = null;
12         if (++takeIndex == items.length)
13             takeIndex = 0;
14         count--;
15         if (itrs != null)
16             itrs.elementDequeued();
17         notFull.signal();
18         return x;
19     }

 

该博客更详细,向博主学习,以后更深入学习后再来完善这篇博客。http://blog.youkuaiyun.com/x_i_y_u_e/article/details/52513038

转载于:https://www.cnblogs.com/boycelee/p/6481519.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值