美文网首页多线程并发tomcat
从tomcat任务队列看ReentrantLock非公平与公平锁

从tomcat任务队列看ReentrantLock非公平与公平锁

作者: 肥兔子爱豆畜子 | 来源:发表于2021-11-05 10:14 被阅读0次

    tomcat的线程池用的任务队列 TaskQueue extends LinkedBlockingQueue<Runnable>,可见是个阻塞队列,里边poll,take这种方法出队之前先要拿锁,源码可以看到是用的ReentrantLock , takeLock = new ReentrantLock()是非公平锁。

    ReentrantLock是基于AQS实现的,内部有两个内部类NonfairSyncFairSync,继承自Sync,而Sync是继承自AQS的。

    我们来走读一下这两个内部类:
    非公平锁实现

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
    
        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1)) //尝试先来一次CAS抢锁
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1); //没拿到就正常acquire,里边是!tryAcquire(arg) && acquireQueued
        }
    
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires); //里边看如果锁0,那么再来一次CAS、成功则返回true;或者锁持有者是当前线程,则重入;其他情况返回false
        }
    }
    

    公平锁实现:

    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
    
        final void lock() {
            acquire(1); //正常acquire,里边是!tryAcquire(arg) && acquireQueued
        }
    
        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&  //无前序节点
                    compareAndSetState(0, acquires)) { //CAS
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) { //当前线程本就持有锁,重入
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }
    
    总结

    LinkedBlockingQueue.poll的时候如果是非公平锁,每个抢锁的线程都可以去尝试CAS先搞2把,没成功则acquireQueued。
    如果是公平锁,则先要判断当前线程在同步队列里没有前序节点才可以CAS尝试1次,如果没成功则acquireQueued。

    相关文章

      网友评论

        本文标题:从tomcat任务队列看ReentrantLock非公平与公平锁

        本文链接:https://www.haomeiwen.com/subject/vczlzltx.html