Reentrantlock源码解析(以非公平锁为例)

加锁操作:

final void lock() {
    if (compareAndSetState(0, 1))    
//CAS操作,判断当前是否有线程加过锁了,如果没有加过,设置成1代表这个线程要给它加锁了   
        setExclusiveOwnerThread(Thread.currentThread());
//把当前加锁对象的主人设置成当前线程
    else
        acquire(1);
//否则代表已经有线程加过锁了,进入后续acquire()方法判断
}

对于compareAndSetState()方法的源码:

    protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

可以看到,本质上调用的是unsafe类的compareAndSwapInt()方法。其中stateOffset代表的是在对象内存中偏移量为stateOffset的变量(也就代指的是volatile修饰的state变量)。state变量就是维护同步状态的重要变量。

进入acquire()方法:

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

这里先会进入tryAcquire()方法:

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }

再进入nonfairTryAcquire()方法:

        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            //获得当前线程ID
            int c = getState();
            //从同步器中获取到state变量,state的值代表锁已重入次数
            if (c == 0) {      //c为0代表还没有线程加锁
                if (compareAndSetState(0, acquires)) {   
            //再判断一下,如果state为0,设置为1
                    setExclusiveOwnerThread(current);    //同时设置持有该锁的线程ID
                    return true;                         //返回加锁成功
                }
            }
            else if (current == getExclusiveOwnerThread()) {  
                //如果state不为0,再判断持有该锁的线程ID是否为当前线程
                int nextc = c + acquires;
                //如果持有该锁的线程ID为当前线程,代表发生了锁重入现象,state加1
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                //判断加锁次数是否int溢出,溢出报错
                setState(nextc);
                //写回state
                return true;                             //返回加锁成功
            }
            return false;                                //返回加锁错误
        }

如果加锁失败,按照   

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

先进入addWaiter(Node.EXCLUSIVE)方法:

    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        //创建一个新节点,线程ID为本线程ID,模式设置为null
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {      //如果尾节点不为空(队列初始化过了)
            node.prev = pred;    //设置该线程代表的节点的前驱节点为尾节点
            if (compareAndSetTail(pred, node)) {     
        //如果尾节点是pred,将尾节点设置为当前线程代表的节点node
        (用的是compareAndSwapObject()方法)
                pred.next = node;
        //设置尾节点的下一个节点为该线程代表的节点(尾插法)
                return node;
        //返回该节点
            }
        }
        enq(node);
        //尾节点为空表示同步队列未被初始化,此时需初始化队列
        return node;
        //初始化完成返回该节点
    }

看看enq()方法:

    private Node enq(final Node node) {  //初始化队列
        for (;;) {            //自旋
            Node t = tail;    
            if (t == null) {                     // (第一次自旋)尾节点为空,代表队列需要初始化
                if (compareAndSetHead(new Node()))   
                    //判断如果头节点为空,则初始化一个头节点
                    tail = head;
                    //让尾节点和头节点指向同一个节点
            } else {                           // (第二次自旋)尾节点不为空,代表队列初始化过了
            //往下都是尾插该节点,调整尾节点为当前节点    
                node.prev = t;                       
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;                        //返回当前节点
                }
            }
        }
    }

将节点插入AQS队列后再进入 acquireQueued()方法:

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {                              
                final Node p = node.predecessor();    
                //判断node的前驱节点是不是头节点,如果是,进入tryAcquire()方法尝试加锁
                if (p == head && tryAcquire(arg)) {
                    //加锁成功后设置头节点
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                //如果加锁失败,则进入shouldParkAfterFailedAcquire()方法,
//如果是第一次进入该方法,该方法会将node的前驱节点的waitstatus的值改为-1并返回false,
//如果是第二次进入该方法,会直接返回true,从而进入parkAndCheckInterrupt()方法来阻塞该线程
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

解锁操作:

    public final boolean release(int arg) {
        if (tryRelease(arg)) {             //true代表当前没有线程持有该锁
            Node h = head;                 
            if (h != null && h.waitStatus != 0)    
           //头节点不为空且头节点的waitStatus不为0
                unparkSuccessor(h);                //唤醒该节点的后继节点
            return true;
        }
        return false;                      //解锁失败返回false
    }

查看tryRelease()方法:

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;          //state值减一
            if (Thread.currentThread() != getExclusiveOwnerThread())
                 //当前线程ID不为持有锁的线程
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                 //c为0代表没有线程持有该锁
                free = true;
                setExclusiveOwnerThread(null);
                 //设置owner线程为空
            }
            setState(c);
            //写回state状态
            return free;
        }

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值