ArrayBlockingQueue详解

ArrayBlockingQueue是由数组实现的阻塞队列,是BlockingQueue的实现类。

特点:

是一个有界的数组,创建的时候传入初始队列大小,

底层采用的是ReentrantLock实现阻塞和用condition条件队列

每次只能生产者和消费者公用一把锁,效率其实一般

底层采用数组存储

=================================================================

Node节点,节点存放pre和next节点,还有一个waitStatus状态,还有存放线程的Thread对象。

讲下CLH同步阻塞队列,是一个双向链表,有个head头和tail尾,操作的元素是Node节点

condition阻塞队列,是个单向链表,有个firstWaiter,和lastWaiter,也是用Node节点

================================================================

创建ArrayBlockingQueue:

传入队列初始大小capacity,初始化一个Object数组,初始化一个ReentrantLock,默认非公平锁,初始化两个condition条件队列,notEmpty(处理消费者线程的)和notFull(处理生产者线程的)

生产过程 put过程:

调用put方法,调用ReentrantLock的lock.lockInterruptibly加可中断锁,(ReentrantLock加锁其实底层是一个CLH队列,维护一个volatile int state=0状态,state=0表示没有线程在加锁,state大于0有线程加锁,采用cas操作进行修改state。没抢到锁的会进入CLH队列,然后SupportLock.park进行阻塞,等待抢到锁的SupportLock.unpark释放锁唤醒。大概是这样)

如果获取到锁,判断数组是否满了(count==数组大小),如果没有满,调用enqueue方法写入数组,维护count++,给notEmpty消费者条件队列发送一个信号(notEmpty.signal()),调用doSinal方法,通知存放在condition队列的消费者Node,enq入队到CLH队列,因为必须要到CLH队列,才能获取到ReentrantLock的锁;

如果数组满了,则notFull条件队列会调用await方法阻塞,把当前获取锁的线程node写入到notFull队列,调用addConditionWaiter进行写入condition入队,      condition里node的waitStatus状态是condition(-2),入完队尝试释放锁,调用fullyRelease方法,在调用release方法释放锁,释放锁会唤醒CLH队列中head后面的第一个node,如果这个node还是生产者,会把生产者node写入到notFull条件队列中,判断如果不在CLH同步队列,会把写入condition队列的node进行阻塞park,等待消费者take消费后singal通知,唤醒在notNull等待队列的生产者

写入成功后调用lock.unlock释放锁。

消费过程take过程:

调用take方法,调用ReentrantLock的lock.lockInterruptibly加可中断锁,判断数组数量是否大于0,如果有数据则调用dequeue进行出队消费,并给notFull发送一个signal通知,让在notFull条件等待队列的生产者enq写入CLH同步队列去获取lock锁,然后唤醒CLH队列第一个node节点。

如果数组为空,则让消费者node进行await阻塞,写入到notEmpty条件队列中,这个过程其实和生产者写入notFull条件队列是一样的。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值