ReentrantLock之lock()

  • lock():
ReentrantLock lock = new ReentrantLock();
lock.lock();
  • 进入lock()
public void lock() {
    sync.lock();
}
//sync.lock(); 分为公平锁和非公平锁(主要区别为:抢锁方式)

//默认为非公平锁
final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

//公平锁
final void lock() {
    acquire(1);
}
  • acquire(1):
public final void acquire(int arg) {
    //tryAcquire(arg):抢锁成功直接退出,失败则走下面代码
    if (!tryAcquire(arg) &&
        //addWaiter(Node.EXCLUSIVE):将当前线程添加在双向队列中
        //acquireQueued(node, arg):将当前线程挂起一个节点状态为-1的节点后面,
        //并且将当前节点的前置状态为1的节点从双向队列中剔除
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        //进入下面节点则说明,当前线程是被interrupt()唤醒的,
        selfInterrupt();
}
  • 分析acquire(1):
//头尾相等->1、都为null。2、目前只有一个节点
public final boolean hasQueuedPredecessors() {
    Node t = tail; 
    Node h = head;
    Node s;
    //头尾不相等、证明队列还存在其他的节点
    return h != t &&
        //(s = h.next) == null  如果为true 
        //说明在生成双向队列的时候,后面的指针指向了前一节点
        //而前面的节点指向后面节点的时候没有成功
        //s.thread != Thread.currentThread()  ture
        //头结点的下一个节点是当前节点
        ((s = h.next) == null || s.thread != Thread.currentThread());
}


//说明有锁的竞争
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
    //如果已经有节点了,将当前节点变成尾结点
    if (pred != null) {
        node.prev = pred;
        //如果有并发操作、这一步失败 将进行 下面的 enq(node)
        //注意此时只是将当前节点的上一个节点指向了尾节点
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}


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;
            }
        }
    }
}


/**
 * node:添加在双向队列中的节点
 * arg:1
 * */
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)) {
                //将当前节点设置为头节点
                //释放当前节点中的线程
                //将当前节点的上一个节点设置为null
                setHead(node);
                // help GC
                p.next = null; 
                failed = false;
                return interrupted;
            }
            //shouldParkAfterFailedAcquire(p, node),确保将当前节点一定要挂载一个状态为-1的节点之后
            //parkAndCheckInterrupt(), 线程挂起
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                //走下面表示线程被interupt唤醒
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}


//获取当前节点的上一个节点
final Node predecessor() throws NullPointerException {
    Node p = prev;
    if (p == null)
        throw new NullPointerException();
    else
        return p;
}

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


//pred 前置节点
//node 当前节点
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    //前置节点状态为-1、可直接挂起线程
    if (ws == Node.SIGNAL)
        return true;
    //前置节点状态为 1 表示已经取消、则将上一个节点从双向队列中剔除
    if (ws > 0) {
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        //将上一个节点的状态、改为-1
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

//线程挂起
private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    //返回当前线程中断标志位
    return Thread.interrupted();
}

//将线程中断标志位设置为 true
static void selfInterrupt() {
    Thread.currentThread().interrupt();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值