简析LinkedBlockingQueue类

此类实现了BlockingQueue接口,同时继承了父类AbstractQueue,父类里实现了几个基本方法的调用
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操作,操作返回的是之前的值。

猜你喜欢

转载自lpbj010.iteye.com/blog/2266176