ArrayBlockingQueue源码解析(JDK1

本文详细解读了JavaReentrantLock类的构造方法,重点介绍了公平锁和非公平锁的区别,以及如何通过`put`和`remove`操作实现队列的入队与出队,涉及了`await`,`signal`等Condition接口的使用。
摘要由CSDN通过智能技术生成

try {

for (E e : c) {

checkNotNull(e);

items[i++] = e;

}

} catch (ArrayIndexOutOfBoundsException ex) {

throw new IllegalArgumentException();

}

count = i;

putIndex = (i == capacity) ? 0 : i;

} finally {

lock.unlock();

}

}

从三个构造方法中可以看出主要是capacity、fair这两个的不同参数

capacity:设置容量,必传值

fair:是否公平,默认值为false,是设置ReentrantLock是公平锁还是非公平锁的

预备知识

ReentrantLock是一个支持响应中断、超时、尝试获取锁,可关联多个条件队列,是个可重入的公平锁和非公平锁。

Condition这个主要是用来实现ReentrantLock的wait和notify的功能

增删改查


入队操作

public void put(E e) throws InterruptedException {

//检验元素是否为空,为null就抛出空指针异常

checkNotNull(e);

//拿到当前的锁

final ReentrantLock lock = this.lock;

//进行锁的抢占

lock.lockInterruptibly();

try {

//当队列长度等于数组长度,表示队列已满,这里使用while来循环等待被唤醒

while (count == items.length)

//put操作时让当前线程处于等待状态

notFull.await();

//当队列没有满并且获取到锁时就进行enqueue入队操作

enqueue(e);

} finally {

//完成锁的释放

lock.unlock();

}

}

private static void checkNotNull(Object v) {

if (v == null)

throw new NullPointerException();

}

private void enqueue(E x) {

// assert lock.getHoldCount() == 1;

// assert items[putIndex] == null;

final Object[] items = this.items;

//设置当前数组putIndex位置的元素为x,这里是尾部插入

items[putIndex] = x;

//putIndex++,然后如果putIndex的大小等于数据的长度,则设置putIndex=0,这里是循环队列的思想

if (++putIndex == items.length)

putIndex = 0;

//元素的个数+1

count++;

//put操作结束,唤醒其他正在处于等待状态的线程

notEmpty.signal();

}

另外offer()函数也可以入队,思路也差不多,也可以了解一下,总结一下入队操作,先检查,然后判断队列没有满并且拿到锁进行入队操作进行设置数组相关位置的值,设置完成,唤醒其他处于等待状态的线程

删除元素

remove()具体元素的出队

public boolean remove(Object o) {

//出队的元素为null,直接返回失败

if (o == null) return false;

//得到数据

final Object[] items = this.items;

//拿到锁

final ReentrantLock lock = this.lock;

//进行锁住操作

lock.lock();

try {

if (count > 0) {

final int putIndex = this.putIndex;

int i = takeIndex;

//循环查找i位置的数据释放就是要删除出队的数据,如果是就进行删除

do {

if (o.equals(items[i])) {

removeAt(i);

return true;

}

if (++i == items.length)

i = 0;

} while (i != putIndex);

}

//元素个数没有大于0直接返回失败

return false;

} finally {

//锁的释放

lock.unlock();

}

}

void removeAt(final int removeIndex) {

// assert lock.getHoldCount() == 1;

// assert items[removeIndex] != null;

// assert removeIndex >= 0 && removeIndex < items.length;

final Object[] items = this.items;

//待删除的下标等于读取的下标

if (removeIndex == takeIndex) {

// removing front item; just advance

//设置数组对应下标的值为null

items[takeIndex] = null;

if (++takeIndex == items.length)

takeIndex = 0;

//元素的个数-1

count–;

//通知所有迭代器头节点出队

if (itrs != null)

itrs.elementDequeued();

} else {

// an “interior” remove

// slide over all others up through putIndex.

final int putIndex = this.putIndex;

//从待删除的下标开始循环查找并设置数据i位置的数据

for (int i = removeIndex;😉 {

int next = i + 1;

if (next == items.length)

next = 0;

if (next != putIndex) {

items[i] = items[next];

i = next;

} else {

items[i] = null;

this.putIndex = i;

break;

}

}

count–;

//通过所有迭代器有内部节点出队

if (itrs != null)

itrs.removedAt(removeIndex);

}

//唤醒其他等待的线程

notFull.signal();

}

take()是队列头数据出队,poll()方法也是一样的

public E take() throws InterruptedException {

final ReentrantLock lock = this.lock;

//尝试去获取锁,如果锁被其他线程占用,那么当前线程就属于等待状态

lock.lockInterruptibly();

try {

//如果元素个数为0,就让当前线程等待,并且释放锁

while (count == 0)

notEmpty.await();

//如果队列不为空,则进行出队,从队列头部取元素

return dequeue();

} finally {

//完成锁的释放

lock.unlock();

}

}

private E dequeue() {

// assert lock.getHoldCount() == 1;

// assert items[takeIndex] != null;

final Object[] items = this.items;

@SuppressWarnings(“unchecked”)

//获取takeIndex位置的元素并将其转换为泛型

E x = (E) items[takeIndex];

//设置takeIndex位置数据为null,便于gc回收

items[takeIndex] = null;

if (++takeIndex == items.length)

takeIndex = 0;

count–;

//通知所有迭代器做相关清理工作

if (itrs != null)

itrs.elementDequeued();

//唤醒其他等待线程

notFull.signal();

return x;

}

上面涉及到了Itrs的两个方法:elementDequeued()、removedAt(),有兴趣的可以看一下具体的实现。

其他方法

contains()查询队列中是否有这个元素

//也运用到了锁,然后循环从takeIndex位置找,找到了就返回true,当takeIndex==putIndex就跳出循环返回false

public boolean contains(Object o) {

//元素为null,

if (o == null) return false;

final Object[] items = this.items;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

结尾

如何才能让我们在面试中对答如流呢?

答案当然是平时在工作或者学习中多提升自身实力的啦,那如何才能正确的学习,有方向的学习呢?为此我整理了一份Android学习资料路线:

这里是一份BAT大厂面试资料专题包:

好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划。来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

结尾

如何才能让我们在面试中对答如流呢?

答案当然是平时在工作或者学习中多提升自身实力的啦,那如何才能正确的学习,有方向的学习呢?为此我整理了一份Android学习资料路线:

[外链图片转存中…(img-ncKF8r4i-1712745714674)]

这里是一份BAT大厂面试资料专题包:

[外链图片转存中…(img-jBMMhl0a-1712745714674)]

好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划。来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值