博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ArrayBlockingQuque摘要
阅读量:4604 次
发布时间:2019-06-09

本文共 2983 字,大约阅读时间需要 9 分钟。

ArrayBlockingQuque

优势

  1. 线程同步,线程安全
  2. 对应空或满时,take\put操作将阻塞
  3. 内部是一个数组,每个元素不会产生额外的处理对象,如Node

基于什么

  • ReentrantLock
  • Condition

解析

构造函数

public ArrayBlockingQueue(int capacity, boolean fair) {    if (capacity <= 0)        throw new IllegalArgumentException();    this.items = new Object[capacity];    lock = new ReentrantLock(fair);    notEmpty = lock.newCondition();    notFull =  lock.newCondition();}
  • 默认创建一个不公平的锁,有利于吞吐量的提高
  • 基于锁创建两个条件,notEmpty\notFull,操作这两个条件的前提必须是已经获取到锁,condition.await()会释放锁进行等待直到被唤醒或中断

非阻塞添加元素 offer(X)

添加元素offer(),offer其实是非阻塞的,添加失败直接放回false

public boolean offer(E e) {    checkNotNull(e);    final ReentrantLock lock = this.lock;    lock.lock();    try {        if (count == items.length)            return false;        else {            enqueue(e);            return true;        }    } finally {        lock.unlock();    }}/** * Inserts element at current put position *  advances, and signals. * Call only when holding lock. */private void enqueue(E x) {    // assert lock.getHoldCount() == 1;    // assert items[putIndex] == null;    final Object[] items = this.items;    items[putIndex] = x;    if (++putIndex == items.length)        putIndex = 0;    count++;    notEmpty.signal();}

offer方法锁定代码块,因此enqueue的操作是安全的,在enque结束后,调用

notEmpty.signal()

唤醒notEmpty.await()状态中的线程,让它退出阻塞,尝试获取锁

阻塞添加元素put

/** * Inserts the specified element at the tail of this *  queue, waiting * for space to become available if the queue is full. * * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */public void put(E e) throws InterruptedException {    checkNotNull(e);    final ReentrantLock lock = this.lock;    lock.lockInterruptibly();    try {        while (count == items.length)            notFull.await();        enqueue(e);    } finally {        lock.unlock();    }}

可以发现,如果count == items.length = true,会一直调用notFull.await()方法,释放锁,且当前线程阻塞等待,直到条件不成立,并且此处await是没有指定超时时间的,意味着它需要被其他线程唤醒

阻塞取走元素take

public E take() throws InterruptedException {    final ReentrantLock lock = this.lock;    lock.lockInterruptibly();    try {        while (count == 0)            notEmpty.await();        return dequeue();    } finally {        lock.unlock();    }}

take方法先获取到锁,锁定代码块,可以看见

while (count == 0)      notEmpty.await();

它的作用是如果没有可take的元素就await,await时释放锁,当前线程陷入睡眠,当offer方法被调用,notEpty.signal()被调用后,take方法的线程从沉睡中醒来,尝试重新获取锁,此时,count == 0 = false,程序进行dequeue

/** * Extracts element at current take position * advances, and signals. * Call only when holding lock. */private E dequeue() {    // assert lock.getHoldCount() == 1;    // assert items[takeIndex] != null;    final Object[] items = this.items;    @SuppressWarnings("unchecked")    E x = (E) items[takeIndex];    items[takeIndex] = null;    if (++takeIndex == items.length)        takeIndex = 0;    count--;    if (itrs != null)        itrs.elementDequeued();    notFull.signal();    return x;}

在获取到元素后,调用notFull.signal(),唤醒阻塞与notFull.await的线程,告诉它可以往队列里面放数据了

转载于:https://www.cnblogs.com/windliu/p/8365677.html

你可能感兴趣的文章
Perl last和next的用法区别
查看>>
Selenium 管理 Cookies
查看>>
exceptionfunction[LeetCode]Permutations
查看>>
Linux(2)_常用命令2
查看>>
自定义分页
查看>>
[转]DELPHI——调试(1)
查看>>
JS秒数转成分秒时间格式
查看>>
xp_cmdshell 命令的开启与关闭,和状态查询
查看>>
Linux sudoers
查看>>
MySQL详解(18)-----------分页方法总结
查看>>
bzoj 4595 激光发生器
查看>>
multi cookie & read bug
查看>>
js时间转换
查看>>
(转载) Android Studio你不知道的调试技巧
查看>>
POJ2231 Moo Volume 递推 C语言
查看>>
struts2类型转换的具体流程
查看>>
Hdu 1203 I NEED A OFFER!
查看>>
php文件上传类
查看>>
CF219D Choosing Capital for Treeland
查看>>
luogu P3809 【模板】后缀排序
查看>>