ArrayBlockingQueue主要源码分析



一、初始化同步阻塞队列 ArrayBlockingQueue

//创建1个同步阻塞队列
ArrayBlockingQueue blockingQueue  = new ArrayBlockingQueue(10);

public ArrayBlockingQueue(int capacity) {
    this(capacity, false);
}
final Object[] items;
public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
        throw new IllegalArgumentException();
    //数组长度为参数传入值,用来存放传入消息
    this.items = new Object[capacity];
    //默认创建一个非公平锁
    lock = new ReentrantLock(fair);
    //用于put监听
    notEmpty = lock.newCondition();
    //用于take监听
    notFull =  lock.newCondition();
}
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

二、调用put方法加入消息

//生产者使用put方法放入消息
public void put(E e) throws InterruptedException {
    //判断放入消息不为空
    checkNotNull(e);
    //获取当前锁
    final ReentrantLock lock = this.lock;
    //加锁
    lock.lockInterruptibly();
    try {
        //判断消息数组是否已满,满了就把当前生产者阻塞
        while (count == items.length)
            notFull.await();
        //添加消息到数组,并且消息数量+1,下标+1,把条件等待队列首个有效节点加入CLH队列
        enqueue(e);
    } finally {
        //添加完消息,释放锁
        lock.unlock();
    }
}

//加锁代码
public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}
public final void acquireInterruptibly(int arg)
        throws InterruptedException {
    //判断是否中断,并清除中断标记 如果中断抛异常
    if (Thread.interrupted())
        throw new InterruptedException();
    //尝试获取锁
    if (!tryAcquire(arg))
        //如果加锁失败,则进入队列
        doAcquireInterruptibly(arg);
}

//尝试获取锁
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
    //获取当前线程
    final Thread current = Thread.currentThread();
    //获取锁状态
    int c = getState();
    //锁状态为0 则说明当前锁没有被其他线程获取
    if (c == 0) {
        // 通过cas比较设置值
        if (compareAndSetState(0, acquires)) {
            //设置获取锁线程为当前线程
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    //判断当前线程和节点线程是否相等,如果相等,说明是重入锁
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

// CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)
// 该操作是一个原子操作,如果执行成功则返回true表示加锁成功
protected final boolean compareAndSetState(int expect, int update) {
    // 这里的this表示当前对象在内存中的位置
    // stateOffset 偏移量 我认为是当前属性在该对象中的内存位置
    // expect 预期原值在这里就是为 0
    // update 新增就是为1
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

//加锁失败,放入CLH队列
private void doAcquireInterruptibly(int arg)
    throws InterruptedException {
    //创建一个当前线程的node节点 Node.EXCLUSIVE=null
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) {
            //获取当前节点的前驱节点
            final Node p = node.predecessor();
            //如果前驱节点为头结点 则再次尝试获取锁
            // 因为很有可能之前的线程已经执行完毕 线程的上下文切换是从用户态切换到内核态是很耗费性能的
            if (p == head && tryAcquire(arg)) {
                //设置当前节点为头节点,并且把线程和前驱节点设置为null 
                setHead(node);
                //把之前头结点的下一个节点设置为null 没有引用后 gc的时候就会回收
                p.next = null; // help GC
                failed = false;
                return;
            }
            //如果前驱节点不是头节点,则修改前驱节点状态,并且和当前节点相连
            if (shouldParkAfterFailedAcquire(p, node) &&
            //使用 LockSupport.park方法阻塞线程
            // 如果调用线程的 Thread.interrupt()方法会中断阻塞,就抛出异常,加锁失败
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

//添加等待节点
private Node addWaiter(Node mode) {
    //创建node节点,线程为当前线程,设置一下等待节点为null
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
     // 判断尾节点不为空,并把当前节点上一个节点设置为之前的尾节点
    if (pred != null) {
        node.prev = pred;
        // cas保证原子操作 并且设置之前尾节点的下一个节点为当前节点
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    //设置node节点进CLH队列
    enq(node);
    return node;
}

//node构造函数
Node(Thread thread, Node mode) {     
    this.nextWaiter = mode;
    this.thread = thread;
}

//设置node节点进队
private Node enq(final Node node) {
    for (;;) {
        //如果队列对空,先初始化队列
        Node t = tail;
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            //不为空的话,
            // cas保证原子操作 并且设置之前尾节点的下一个节点为当前节点
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

//设置头节点
private void setHead(Node node) {
    head = node;
    node.thread = null;
    node.prev = null;
}

//设置前前驱节点状态,并且和当前节点相连
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    //前驱节点第一次进来时为0 所以只会走到当前方法的else
    int ws = pred.waitStatus;
    //第二次进来前驱节点为-1,所以直接返回true
    if (ws == Node.SIGNAL)
        return true;
    //如果前驱节点waitStatus状态大于0,表示该节点已损坏,不可用。则把pred节点踢出当前队列
    if (ws > 0) {
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        //设置 pred节点为-1表示后续节点node可唤醒
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}

//阻塞当前线程
public final void await() throws InterruptedException {
    //判断是否使用 interrupt方法中断线程
    if (Thread.interrupted())
        throw new InterruptedException();
    //把当前线程加入条件等待队列
    Node node = addConditionWaiter();
    //释放锁,返回锁状态
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    //判断当前节点属于CLH还是条件等待队列
    while (!isOnSyncQueue(node)) {
        //如果当前节点为等待队列节点,则阻塞
        //一般put到这里就结束了,因为park方法会把当前线程阻塞
        LockSupport.park(this);
        //阻塞结束后,判断当前线程是否被interrupt方法中断,如果中断则返回0,循环继续判断node节点
        //否则根据判断属于CLH、条件等待队列返回-1,1
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    //如果while没有进入,或者解除阻塞后,尝试重新获取锁,并且把当前节点状态设置为-1,表示可唤醒
    //如果 interruptMode=1,
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
        //遍历所有条件等待队列节点,保证有效性
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
        //如果是1或者-1表示在队列中,则抛异常,或者中断当前线程
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

//把当前线程加入条件等待队列
private Node addConditionWaiter() {
    //获取条件等待队列尾节点
    Node t = lastWaiter;
    //如果尾节点不为null并且 节点状态不为-2
    if (t != null && t.waitStatus != Node.CONDITION) {
        //遍历整个条件等待队列,把失效节点剔除
        unlinkCancelledWaiters();
        //重新获取尾节点,保证有效性
        t = lastWaiter;
    }
    //为当前线程初始化节点
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    //加入条件等待队列,并且设置为尾节点
    if (t == null)
        firstWaiter = node;
    else
        t.nextWaiter = node;
    lastWaiter = node;
    return node;
}

//遍历整个条件等待队列,把失效节点剔除
private void unlinkCancelledWaiters() {
    //获取条件等待队列首节点
    Node t = firstWaiter;
    Node trail = null;
    while (t != null) {
        //获取首节点下一个节点
        Node next = t.nextWaiter;
        //在循环中,如果第一个节点状态不为-2,
        //会把firstWaiter指向下一个节点,并把等节点的nextWaiter设置为null
        //循环中,如果节点状态等于-2,会把trail指向t
        //下次循环中,如果节点状态不等于-2,会把之前有效节点trail的nextWaiter指向next
        if (t.waitStatus != Node.CONDITION) {
            t.nextWaiter = null;
            if (trail == null)
                firstWaiter = next;
            else
                trail.nextWaiter = next;
            if (next == null)
                lastWaiter = trail;
        }
        else
            trail = t;
        t = next;
    }
}

final int fullyRelease(Node node) {
    boolean failed = true;
    try {
        //获取当前锁状态
        int savedState = getState();
        //释放锁
        if (release(savedState)) {
            failed = false;
            return savedState;
        } else {
            throw new IllegalMonitorStateException();
        }
    } finally {
        //如果释放锁失败,则把当前节点设置为1,表示废除
        if (failed)
            node.waitStatus = Node.CANCELLED;
    }
}

//释放锁
public final boolean release(int arg) {
    //释放锁
    if (tryRelease(arg)) {
        //获取头结点
        Node h = head;
        //判断头结点状态,是否被可以唤醒
        if (h != null && h.waitStatus != 0)
        //唤醒clh队列中等待最久节点
            unparkSuccessor(h);
        return true;
    }
    return false;
}

protected final boolean tryRelease(int releases) {
    //加锁状态为1 所以正常结果c就是0
    int c = getState() - releases;
    //判断当前线程等于当前节点线程
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    //c为0,表示锁状态正确,并且把state状态设置为0
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

protected final void setState(int newState) {
    state = newState;
}

//唤醒clh队列中等待最久节点
private void unparkSuccessor(Node node) {
    int ws = node.waitStatus;
    //首节点状态小于0,后续节点可以用唤醒
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        //如果首节点的下一个节点为null或者状态大于0,则从clh队列尾部遍历获取可唤醒的节点
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    //唤醒线程
    if (s != null)
        LockSupport.unpark(s.thread);
}

//判断节点属于条件等待队列还是CLH队列
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);
}

//判断当前节点归属
private boolean findNodeFromTail(Node node) {
    Node t = tail;
    for (;;) {
        if (t == node)
            return true;
        if (t == null)
            return false;
        t = t.prev;
    }
}

//判断当前线程是否被interrupt方法中断,如果中断则返回0
//否则根据判断属于CLH、条件等待队列返回-1,1
private int checkInterruptWhileWaiting(Node node) {
    return Thread.interrupted() ?
        (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
        0;
}

//如果是CLH队列节点返回true,如果是条件等待队列节点返回false
final boolean transferAfterCancelledWait(Node node) {
    //如果更新成功,则讲该节点放入CLH队列
    if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
        enq(node);
        return true;
    }
    //如果当前节点为条件等待队列节点,则让出线程
    while (!isOnSyncQueue(node))
        Thread.yield();
    return false;
}

//添加消息到数组,并且消息数量+1,下标+1
private void enqueue(E x) {
    final Object[] items = this.items;
    items[putIndex] = x;
    if (++putIndex == items.length)
        putIndex = 0;
    count++;
    //把条件等待队列首个有效节点加入CLH队列
    notEmpty.signal();
}

//把条件等待队列首个有效节点加入CLH队列
public final void signal() {
    //判断当前线程是否和节点线程相等
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    //获取条件等待队列首节点,   
    Node first = firstWaiter;
    //把条件等待队列节点入CLH队列
    if (first != null)
        doSignal(first);
}

//把条件等待队列节点入CLH队列
private void doSignal(Node first) {
    do {
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
        //如果条件等待节点队列放入CLH队列失败,则继续查找一个可放入的
    } while (!transferForSignal(first) &&
             (first = firstWaiter) != null);
}

//把条件等待队列节点入CLH队列
final boolean transferForSignal(Node node) {
    //把条件等待节点队列节点状态设置为0
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        return false;
    //放入CLH队列,并且返回前一个节点
    Node p = enq(node);
    //获取节点状态,正常结果就是0
    int ws = p.waitStatus;
    //把节点状态设置为可唤醒状态-1,如果设置失败,则唤醒节点线程
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        LockSupport.unpark(node.thread);
    return true;
}

//释放锁
public void unlock() {
    sync.release(1);
}
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
        //唤醒clh队列中等待最久节点
            unparkSuccessor(h);
        return true;
    }
    return false;
}

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

//该方法的调用,只有在节点状态为1,表示节点失效,才会调用
private void cancelAcquire(Node node) {
    // Ignore if node doesn't exist
    if (node == null)
        return;
    node.thread = null;
    //CLH队列去除失效节点
    Node pred = node.prev;
    while (pred.waitStatus > 0)
        node.prev = pred = pred.prev;
    //获取前驱节点    
    Node predNext = pred.next;
    //当前节点设置为失效状态
    node.waitStatus = Node.CANCELLED;
    //把失效节点的前驱节点的next指针设置为null
    if (node == tail && compareAndSetTail(node, pred)) {
        compareAndSetNext(pred, predNext, null);
    } else {
        // If successor needs signal, try to set pred's next-link
        // so it will get one. Otherwise wake it up to propagate.
        int ws;
        if (pred != head &&
            ((ws = pred.waitStatus) == Node.SIGNAL ||
             (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
            pred.thread != null) {
            Node next = node.next;
            //node节点失效后,把node的pred节点和node的next节点串联起来
            if (next != null && next.waitStatus <= 0)
                compareAndSetNext(pred, predNext, next);
        } else {
           //唤醒clh队列中等待最久节点
            unparkSuccessor(node);
        }
        //去除node引用,保证GC
        node.next = node; // help GC
    }
}

三、调用take方法获取消息

public E take() throws InterruptedException {
    //获取当前锁,并且加锁
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        //如果当数组中的消息数量为0,则把消费者都阻塞,并且加入条件等待队列
        //与上面put方法逻辑相同
        while (count == 0)
            notEmpty.await();
        //返回消息
        return dequeue();
    } finally {
        //释放锁
        lock.unlock();
    }
}

//获取消息方法
private E dequeue() {
    //获取当前数组
    final Object[] items = this.items;
    @SuppressWarnings("unchecked")
    //第一次进来,takeIndex=0,所以获取第一个消息
    E x = (E) items[takeIndex];
    //把一个消息对象设置为Null
    items[takeIndex] = null;
    if (++takeIndex == items.length)
        takeIndex = 0;
    count--;
    if (itrs != null)
        itrs.elementDequeued();
    notFull.signal();
    return x;
}

总结

在ArrayBlockingQueue中,主要用到了ReentrantLock加锁来保证对数组对象操作的原子性。(AQS使用到了自旋、CAS、LockSupport、队列(CLH队列、条件等待队列))。
1.初始化队列的时候,需要指定一个长度(new ArrayBlockingQueue(10)),用来初始化数组,存放生产者产生的消息。并且创建ReentrantLock锁,来保证对数组对象操作的原子性。
2.使用put()方法的时候,首先通过lockInterruptibly方法获取当前去加锁,如果加锁成功,会去判断数组对象是否已满,如果已满,调用await方法会把当前生产者加入条件等待队列中,去唤醒CLH的头节点,然后释放锁并把当前生产者线程阻塞。当调用take方法时候,会判断count==0的时候把条件等待队列节点加入CLH列并唤醒。然后释放锁

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值