java-并发-源码-BlockingQueue
一.BlockingQueue
ArrayBlockingQueue和LinkedBlockingQueue的区别:
- 队列中锁的实现不同
 ArrayBlockingQueue实现的队列中的锁是没有分离的,即生产和消费用的是同一个锁;
 LinkedBlockingQueue实现的队列中的锁是分离的,即生产用的是putLock,消费是takeLock
- 在生产或消费时操作不同
 ArrayBlockingQueue实现的队列中在生产和消费的时候,是直接将枚举对象插入或移除的;
 LinkedBlockingQueue实现的队列中在生产和消费的时候,需要把枚举对象转换为Node进行插入或移除,会影响性能 
- 队列大小初始化方式不同
 ArrayBlockingQueue实现的队列中必须指定队列的大小;
 LinkedBlockingQueue实现的队列中可以不指定队列的大小,但是默认是Integer.MAX_VALUE
| 可能报异常 | 返回布尔值 | 可能阻塞 | 设定等待时间 | |
|---|---|---|---|---|
| 入队 | add(e) | offer(e) | put(e) | offer(e, timeout, unit) | 
| 出队 | remove() | poll() | take() | poll(timeout, unit) | 
| 查看 | element() | peek() | 无 | 无 | 
add(e) remove() element() 方法不会阻塞线程。
offer(e) poll() peek() 方法即不会阻塞线程,也不会抛出异常。
要想要实现阻塞功能,需要调用put(e) take() 方法。当不满足约束条件时,会阻塞线程。
二.ArrayBlockingQueue
这是一个循环队列,index到结尾了,会从头部开始
    final ReentrantLock lock;
    private final Condition notEmpty;
    private final Condition notFull;
    final Object[] items;
    int takeIndex;
    int putIndex;
    int count;
内部位置一个ReentrantLock和这个锁创建的两个condition
items是创建时指定大小的数组
count是存储了多少个元素
putIndex是队尾指针
takeIndex是队头指针
put代码
    public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }
put代码,如果满了需要等待在notFull这condition里,等待非满信号
take代码
  public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
如果队列空了,需要等待在notEmpty这个condition里,等待非空信号;
put和take是生产者消费者模式
enqueue(e)是生产对象,填进队列中;生产完之后,会发出非空信号;
dequeue()是消费对象,并且返回;消费完之后,会发出非满信号;
enqueue代码
   private void enqueue(E x) {
        final Object[] items = this.items;
        items[putIndex] = x;
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        notEmpty.signal();
    }
dequeue代码
    private E dequeue() {
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        notFull.signal();
        return x;
    }
三.ReentrantLock的lockInterruptibly方法
put调用了ReentrantLock得lockInterruptibly方法进行锁定
调用关系lockInterruptibly->sync.acquireInterruptibly(1)代码如下
   public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }
如果尝试没有获取到锁,那么执行doAcquireInterruptibly(1),如下
private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
增加一个等待链表,所有尝试获取的线程都会阻塞
park方法如下,调用park应该是会阻塞,如果被中断,Thread.interrupted()应该会返回true,因为抛出中断异常
    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, 0L);
        setBlocker(t, null);
    }
四.ReentrantLock的condition和awiait
构造时创建了condition
	notEmpty = lock.newCondition();
	notFull =  lock.newCondition();
AQS中有ConditionObject实现,具有如下成员
    private transient Node firstWaiter;
    private transient Node lastWaiter;
await
代码如下:
   public final void await() throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        Node node = addConditionWaiter();
        int savedState = fullyRelease(node);
        int interruptMode = 0;
        while (!isOnSyncQueue(node)) {
            LockSupport.park(this);
            ...
        }
        ...
    }
await调用addConditionWaiter创建等待链表,返回最后一个结点
调用fullyRelease释放掉该node占用的Reentranlock
链表节点创建时指定了Node.CONDITION,所以isOnSyncQueue都返回false
   final boolean isOnSyncQueue(Node node) {
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        if (node.next != null) // If has successor, it must be on queue
            return true;
        return findNodeFromTail(node);
    }
因此线程会锁在LockSupport.park(this)的位置
signal
 	public final void signal() {
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
        Node first = firstWaiter;
        if (first != null)
            doSignal(first);
    }
signal调用了doSignal方法,向链表中第一个节点发信号
 	private void doSignal(Node first) {
        do {
            if ( (firstWaiter = first.nextWaiter) == null)
                lastWaiter = null;
            first.nextWaiter = null;
        } while (!transferForSignal(first) &&
                 (first = firstWaiter) != null);
    }
transferForSignal
把节点从condition队列转到sync队列,同时把状态修改为signal,如果有很多线程,会产生一个链表
 	final boolean transferForSignal(Node node) {
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))	//node类型设置为0
            return false;
        Node p = enq(node);	//生成一队node队列
        int ws = p.waitStatus;
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }
这个时候等待线程unpark,继续执行阻塞前的代码
继续await代码
 	public final void await() throws InterruptedException {
	    ...
        while (!isOnSyncQueue(node)) {
            ...
        }
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            interruptMode = REINTERRUPT;
        if (node.nextWaiter != null) // clean up if cancelled
            unlinkCancelledWaiters();
        if (interruptMode != 0)
            reportInterruptAfterWait(interruptMode);
    }
由于进入了同步队列,跳出while循环
acquireQueued使线程形成一个阻塞队列,抢占到cpu的线程恢复state状态
 
                    
                
 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号