LinkedBlockingQueue源码阅读

128 阅读3分钟

LinkedBlockingQueue简介

  • Linked:由链表实现,Blocking:支持阻塞获取和添加,Queue:一个队列

  • 和经典的生产者消费者不同的是:生产者和消费者各使用一把锁

  • 生产者阻塞后由大概率由生产者唤醒,小概率被消费者唤醒,消费者同理

		
	//队列结点
    static class Node {
        E item;
		
        Node next;
		
        Node(E x) { item = x; }
    }
	
	//队列容量
    private final int capacity;

    //结点数量
    private final AtomicInteger count = new AtomicInteger();

    //头结点
    transient Node head;

    //尾结点
    private transient Node last;

    //take,poll操作使用的锁
    private final ReentrantLock takeLock = new ReentrantLock();

    //当take,poll条件不满足时,使用notEmpty队列等待
    private final Condition notEmpty = takeLock.newCondition();

    //put,offer操作使用的锁
    private final ReentrantLock putLock = new ReentrantLock();

    //当put,offer条件不满足时,使用notFull队列等待
    private final Condition notFull = putLock.newCondition();
	
	//初始化容量为Intger最大值
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

    //构造函数:初始化容量和头尾结点
	//头结点不存储值
    public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node(null);
    }
	

解析put()和offer()

		
    public void put(E e) throws InterruptedException {
		
		//空指针异常
        if (e == null) throw new NullPointerException();
		
		//count
        int c = -1;
		
		//把要放入的值包装成Node结点
        Node node = new Node(e);
		
		//put锁
        final ReentrantLock putLock = this.putLock;
		
		//队列中的结点数目
        final AtomicInteger count = this.count;
		
		//拿锁,具体见AQS源码阅读(一)
        putLock.lockInterruptibly();
        try {
            
			//队列满了,去notFull队列等待,await()操作具体见AQS源码阅读(二)
            while (count.get() == capacity) {
                notFull.await();
            }
			
			//更新尾结点:将结点入队
            enqueue(node);
			
			//count自增一
            c = count.getAndIncrement();
			
			//此时队列还有容量,可以添加,去唤醒notFull队列中的结点,signal()操作具体见AQS源码阅读(二)
            if (c + 1 < capacity)
                notFull.signal();
        } finally {
			
			//解锁,具体见AQS源码阅读(一)
            putLock.unlock();
        }
        if (c == 0)
			
			//什么时候c == 0?
			//当前线程添加时队列为空,消费者都阻塞了,需要由生产者去唤醒消费者 
            signalNotEmpty();
    }
	
	//更新尾结点:将node入队
	private void enqueue(Node node) {
        // assert putLock.isHeldByCurrentThread();
        // assert last.next == null;
        last = last.next = node;
    }
	
	//唤醒notEmpty队列中的一个结点
	private void signalNotEmpty() {
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lock();
        try {
            notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
    }
	
	//和put()不同,offer操作不会阻塞,如果无法添加就返回了
	public boolean offer(E e) {
		
		//空指针异常
        if (e == null) throw new NullPointerException();
		
		//队列中的结点数目
        final AtomicInteger count = this.count;
		
		//队列容量已满,直接返回
        if (count.get() == capacity)
            return false;
		
		//count
        int c = -1;
		
		//把要放入的值包装成Node结点
        Node node = new Node(e);
		
		//put锁
        final ReentrantLock putLock = this.putLock;
		
		//拿锁
        putLock.lock();
        try {
			
			//添加结点
            if (count.get() < capacity) {
                enqueue(node);
				
				//count自增一
                c = count.getAndIncrement();
				
				//此时队列还有容量,可以添加,去唤醒notFull队列中的结点
                if (c + 1 < capacity)
                    notFull.signal();
            }
        } finally {
			
			//解锁
            putLock.unlock();
        }
        if (c == 0)
			
			//什么时候c == 0?
			//当前线程添加时队列为空,消费者都阻塞了,需要由生产者去唤醒消费者 
            signalNotEmpty();
			
		//如果添加成功会更新c	
        return c >= 0;
    }
	

解析take()和poll()

		
	public E take() throws InterruptedException {
		
		//要拿的值
        E x;
		
		//count
        int c = -1;
		
		//队列中的结点数目
        final AtomicInteger count = this.count;
		
		//take锁
        final ReentrantLock takeLock = this.takeLock;
		
		//拿锁
        takeLock.lockInterruptibly();
        try {
			
			//队列为空,去notEmpty队列等待
            while (count.get() == 0) {
                notEmpty.await();
            }
			
			//从head.next处取值,并更新head
            x = dequeue();
			
			//count自减一
            c = count.getAndDecrement();
			
			//此时队列还可以拿,去唤醒notEmpty队列中的结点
            if (c > 1)
                notEmpty.signal();
        } finally {
			
			//解锁
            takeLock.unlock();
        }
		
		//什么时候c == capacity?
		//当前线程消费时队列满载,生产者都阻塞了,需要由消费者去唤醒生产者
        if (c == capacity)
            signalNotFull();
        return x;
    }
	
	//从head.next处取值,更新头结点
	private E dequeue() {
        // assert takeLock.isHeldByCurrentThread();
        // assert head.item == null;
        Node h = head;
        Node first = h.next;
        h.next = h; // help GC
        head = first;
        E x = first.item;
        first.item = null;
        return x;
    }
	
	//唤醒notFull队列中的一个结点
	private void signalNotFull() {
        final ReentrantLock putLock = this.putLock;
        putLock.lock();
        try {
            notFull.signal();
        } finally {
            putLock.unlock();
        }
    }

    public E poll() {
		
		//队列中的结点数目
        final AtomicInteger count = this.count;
		
		//队列为空,直接返回
        if (count.get() == 0)
            return null;
		
		//要拿的值
        E x = null;
		
		//count
        int c = -1;
		
		//take锁
        final ReentrantLock takeLock = this.takeLock;
		
		//拿锁
        takeLock.lock();
        try {
            if (count.get() > 0) {
				
				//从head.next处取值,并更新head
                x = dequeue();
				
				//count自减一
                c = count.getAndDecrement();
                if (c > 1)
					
					//此时队列还可以拿,去唤醒notEmpty队列中的结点
                    notEmpty.signal();
            }
        } finally {
			
			//解锁
            takeLock.unlock();
        }
		//什么时候c == capacity?
		//当前线程消费时队列满载,生产者都阻塞了,需要由消费者去唤醒生产者
        if (c == capacity)
            signalNotFull();
        return x;
    }