简介
LinkedBlockingQueue以链表(单链表)为基础实现的队列,先进先出,head是队列中存在最久的元素,tail是最新加入的元素,添加元素从队尾添加;删除元素,从队头删除;
不容许插入null;线程安全,用ReentrantLock实现线程安全;用法和ArrayBlockingQueue一致
AtomicInteger类
AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。
public final int get() //获取当前的值
public final int getAndSet(int newValue)//获取当前的值,并设置新的值
public final int getAndIncrement()//获取当前的值,并自增
public final int getAndDecrement() //获取当前的值,并自减
public final int getAndAdd(int delta) //获取当前的值,并加上预期的值
构造函数
构造函数:默认容量是Integer.MAX;也可以指定固定容量
Java是自右向左逐一赋值的,比如:A=B=C=0,首先给C赋值0,即C=0,然后B=C;最后A=B。
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
//先给head赋值;再给last赋值head;(last,head都指向同一内存地址),此时head,last节点的值都为null,并且next都指向null;
last = head = new Node<E>(null);
}
添加 add(),offer(),put()
add()方法:队列没满之前,直接添加,返回true;否则报队列已满异常;
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
offer():是否添加成功;队列已满,添加失败,返回false;未满,添加成功,返回true;
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
//判断容量是否已满
if (count.get() == capacity)
return false;
int c = -1;
//创建新的节点
Node<E> node = new Node<E>(e);
//插入锁
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
//队列未满
if (count.get() < capacity) {
enqueue(node);
//获取当前的值,并且自增;添加成功之后,+1判断队列是否已满;未满,唤醒一个在await队列的线程;
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
}
} finally {
putLock.unlock();
}
//非空 唤醒一个在await队列的线程;
if (c == 0)
signalNotEmpty();
return c >= 0;
}
enqueue():在队尾添加元素节点;在链表末端加上一个新节点;
Java是自右向左逐一赋值的,比如:A=B=C=0,首先给C赋值0,即C=0,然后B=C;最后A=B。
private void enqueue(Node<E> node) {
// assert putLock.isHeldByCurrentThread();
// assert last.next == null;
//先给last.next赋值node;即此时head,last节点的next引用都指向node节点;
//再给last赋值last.next(即node节点);即last = node;
//综上所述:队列初始化后,队列插入第一个元素时,就给head的next引用赋值了;非第一次插入元素,只改变last;
last = last.next = node;
}
put():插入时,队列已满,则线程阻塞;否则直接插入;
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
//队列已满,则线程阻塞
while (count.get() == capacity) {
notFull.await();
}
//在队列尾插入新节点
enqueue(node);
c = count.getAndIncrement();
//判断容量是否已满;
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
//队列是否为空;
if (c == 0)
signalNotEmpty();
}
获取队头元素:element(),peek()
element():队列不为空,返回队列头的元素值;否则报异常;
public E element() {
E x = peek();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
peek():队列为空,返回null;不为空,返回队列头的元素值;
public E peek() {
if (count.get() == 0)
return null;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
//head对象next引用在插入操作调用enqueue()就赋值了,指向队列头节点;
return (count.get() > 0) ? head.next.item : null;
} finally {
takeLock.unlock();
}
}
删除 poll(),take(),remove()
poll():从队尾删除,队列为空,直接返回null;不为空,返回删除的节点的值;
public E poll() {
final AtomicInteger count = this.count;
//队列为空
if (count.get() == 0)
return null;
E x = null;
int c = -1;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
//队列不为空
if (count.get() > 0) {
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
}
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
dequeue():返回队列头结点的值;
private E dequeue() {
// assert takeLock.isHeldByCurrentThread();
// assert head.item == null;
//此时head 的值为null,next指向队列头结点;赋值给节点h;
Node<E> h = head;
//队列头节点;
Node<E> first = h.next;
h.next = h; // help GC
//将head赋值
head = first;
//取出值x;
E x = first.item;
//把值置为null,称为正式的头结点,其next引用指向队列头结点;
first.item = null;
return x;
}
take():如果队列为空,线程阻塞;不为空,直接返回队列头结点对应的值;
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
remove():从队列中删除某个对象,true 队列存在该元素,并删除成功;false 队列不存在该元素;
public boolean remove(Object o) {
if (o == null) return false;
fullyLock();
try {
//从头结点开始遍历,确认是否存在该对象
for (Node<E> trail = head, p = trail.next;
p != null;
trail = p, p = p.next) {
if (o.equals(p.item)) {
unlink(p, trail);
return true;
}
}
return false;
} finally {
fullyUnlock();
}
}
unlink()方法:
//p节点时要删除的节点;trail是p节点的上一个节点
void unlink(Node<E> p, Node<E> trail) {
//将p节点的值设为null;
p.item = null;
//trail指向p节点的下一个节点;
trail.next = p.next;
//如果p是队尾节点,则last=trail;
if (last == p)
last = trail;
//非满队列 唤醒对应await队列一个线程
if (count.getAndDecrement() == capacity)
notFull.signal();
}
以上就是LinkedBlockingQueue的主要方法分析,如有问题,请多指教,谢谢!