1. ArrayBlockingQueue
Queue queue =new ArrayBlockingQueue(1);
//构造器
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();
}
queue .add(1);
在queue里面新增数据,这个数据容量已经满了就会抛出一个IllegalStateException异常,如果offer(e);
public boolean add(E e) {
//下个就是说明offer什么时候是false
if (offer(e))
return true;
else
.//如果offer是false就抛出错误
throw new IllegalStateException("Queue full");
}
offer(e)代码
在queue里面新增数据,这个数据容量已经满了返回false
public boolean offer(E e) {
checkNotNull(e);
//有个一个全局的lock锁,说明arrayBlockQueue是add是会加锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
//如果容量满了就抛出异常
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
这里是由个锁,如果count == items.length 容量相同就放回false,所以这个可以看看如果使用offer,容量满了就返回false,如果是用add就会抛出异常
接着我们看下,enqueue(e)
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
//把需要新增的值放入的items里面
items[putIndex] = x;
// 判断是容量是否满了
//判断完以后putindex+1
if (++putIndex == items.length;
putIndex = 0;
count++;
notEmpty.signal();
}
notEmpty.signal();
public final void signal() {
//是否当前的线程
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
再看一个时间,可以进行等待,如果容量已经满的话
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
checkNotNull(e);
//转化时间可以进入看看源码,其实就是一个Eum然后,重新方法
//这个方法开始还整没用弄明白后来发现是一个转化,及时更加转化为毫秒,秒,分等
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
//如果为0,就部需要等待,如容量已经满
if (nanos <= 0)
return false;
//这层代码可以有空看看
nanos = notFull.awaitNanos(nanos);
}
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
poll
锁定使用的lock,会一直等待下去
获取成功后,在take就是获取下个坐标
public E poll() {
final ReentrantLock lock = this.lock;
//会一直等下去
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
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;
//从0开始取值
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();
return x;
}
take
更poll不同的是,这边的锁使用lockinterruptibly(),这个锁的意思是遇到Thread.interrup,就会抛出异常,不在等待下去,
获取成功后,在take就是获取下个坐标
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
// 允許被中斷如何使用Thread.interrupt就抛出异常
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
peek
获取头列,不修改其他参数,在获取还是该值
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//获取数列值
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
remainingCapacity:剩余的容量
public int remainingCapacity() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//总共的进行减去
return items.length - count;
} finally {
lock.unlock();
}
}
removeAt 这个代码有点逻辑,可以看看,如果不是最后一个就是一个链路
1、首先判断下,如果是最后一个链路要删除的,那么直接把最后链路数据为null赋值,然后修改put的坐标为赋值为null的下坐标
2、如果如果删除的next坐标链路正好是你put坐标,那么直接赋值我null,然后修改put向前进一个坐标
3、如果删除不是最后一个或也不是put最后一个,那么让他下一个数据去覆盖他本身数据,然后循环,下个链路数据覆盖上个链路数据,直到next=put的index,然后进行赋值为null,
public boolean remove(Object o) {
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;
do {
if (o.equals(items[i])) {
removeAt(i);
return true;
}
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
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
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
} else {
// an "interior" remove
// slide over all others up through putIndex.
//不是最后一个逻辑,putIndex
final int putIndex = this.putIndex;
for (int i = removeIndex;;) {
int next = i + 1;
//如果说明最后一个next=0
if (next == items.length)
next = 0;
if (next != putIndex) {
items[i] = items[next];
i = next;
} else {
//说明是最后一个next=putIndex,next+1就是我下个要发的index,那么说明移除的就是最后一个,直接返回
items[i] = null;
// 从去掉i进行放值
this.putIndex = i;
break;
}
}
count--;
if (itrs != null)
itrs.removedAt(removeIndex);
}
//通知
notFull.signal();
}
ArrayBlockqueue总结:
需要容量的阻塞的队列,
take或poll:都是获取列头数据,获取成功后,下次take或poll移动下个链路上,两个区别在于,poll会一直等下去,但是take中使用的lock.interruptibly如果遇到Thread.interrup,会抛出异常
and:如果容量满会抛出异常,加锁方式为:lock.lock
offer:返回的false,加锁方式为:lock.lock
peek:获取当前指标所值数据,对游标不做处理(小G暂且这样说,及时take和poll,没次获取他下坐标都会执行下个链路)也是加锁的
remove:移除下坐标数据,移除加锁,然后找到对应的下标游,然后再进行获取, 加锁方式为:lock.lock
contains和remove,clear 都是加锁的