add(E e),通过子类的offer(e)具体实现
remove(),通过子类的poll()具体实现
element(),通过子类的peek()具体实现,这几个是常用方法
在LinkedBlockingQueue中,先定义了个Node内部类,这个类是队列中存储的具体的节点类,所以的通过泛型定义的类型都会封装成Node类存储在队列里
static class Node<E> { //加static 可以在类中直接定义,不用加外部类名的前缀 E item; //定义某个泛型类型变量,存储具体的值 Node<E> next; //队列里链表存储机制,这个是定义下一个的节点 Node(E x) { item = x; } } final int capacity; //定义此队列的长度,默认是Integer的最大长度Integer.MAX_VALUE final AtomicInteger count = new AtomicInteger(0); //当前队列的已有个数,定义成AtomicInteger可以在底层实现CAS的原子操作
signalNotEmpty()和signalNotFull()方法在多线程情况下,生产者和消费者模式里进行唤醒操作,类似Object中的notify()方法
队列真实添加节点的方法,所有的入队都会调用 private void enqueue(Node<E> node) { last = last.next = node; //这句代码相当于 last.next = node; last = last.next; 把节点赋值给最后节点的下一个,最后节点往后推一个 } 与之对应的是所有的出队都会调用的方法,取头结点指向的节点 private E dequeue() { Node<E> h = head; Node<E> first = h.next; //获取头结点的下一个节点 first h.next = h; // help GC //释放最开始的头结点 head = first; //把first当做头结点 E x = first.item; first.item = null; //清空头结点的具体值 return x; } 进队方法,基本上进队都是类似操作 public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); int c = -1; Node<E> node = new Node(e); final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; putLock.lockInterruptibly(); try { while (count.get() == capacity) { //如果队列已满,入队锁里的notFull条件生效,开始等待 notFull.await(); } enqueue(node); c = count.getAndIncrement(); //没加这个节点之前,队列中节点个数 if (c + 1 < capacity) //加完这个节点后如果还有空地,唤醒一个入队锁里的在notFull条件等待的线程 notFull.signal(); } finally { putLock.unlock(); } if (c == 0) //如果在加入这个节点前,队列为空,则唤醒一个在出队锁里,在notEmpty条件等待的线程 signalNotEmpty(); } 出队方法,基本上出队都是类似操作 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条件生效,开始等待 notEmpty.await(); } x = dequeue(); c = count.getAndDecrement(); if (c > 1) //取出这个节点后如果队列还有值,唤醒一个出队锁里的在notEmpty条件等待的线程 notEmpty.signal(); } finally { takeLock.unlock(); } if (c == capacity) //如果在取出这个节点前,队列是满的,则唤醒一个在入队锁里,在notFull条件等待的线程 signalNotFull(); return x; }
其他出队入队的方法类似这两个方法,就不多说了。
这个类主要是注意这个队列是用链表进行存储,头结点的item是null,next指向了第一个节点。在多线程同步的时候用了ReentrantLock,定义了出队锁和入队锁,每个所都有自己的condition,所以唤醒的时候回相对精确唤醒某种类型的await。用了AtomicInteger对象做计数器,这个类实现了加减的CAS操作,操作返回的是之前的值。