Java中的ReentrantLock

ReentrantLock是java并发包(Java.util.concurrent)下,基于AbstractQueuedSynchronizer实现的可重入的互斥锁

AbstractQueuedSynchronizer

AQS是java并发包下的一个抽象类,不能使用它直接创建一个对象

具体锁的实现需要通过继承AQS

底层结构

AQS底层是基于双向队列(同步队列)实现的,类中维护了三个成员变量:

  1. 一个是int类型的STATE: 用于标记当前锁的状态
  2. 一个头节点:HEAD
  3. 一个尾节点:TAIL

每当有线程竞争锁失败后,会将该线程包装成一个Node放入双向队列(同步队列)中

同步队列为空时,会先创建一个空的头节点,里面没有线程任何信息,然后再将竞争失败的Node节点添加到同步队列中(因为等待锁的节点需要被前一个节点唤醒)

Node节点存放的信息:

  1. waitStatus:当前节点的状态
    1. 0:节点创建好之后的默认状态
    2. SIGNAL(-1):当前节点需要唤醒下一个节点
    3. CANCELLED(1):当前节点被取消,不再参与锁的竞争
    4. CONDITION(-2):节点在条件队列中等待
    5. PROPAGATE(-3):共享模式下需传播唤醒信号
  2. prev:前驱指针
  3. next:后继指针
  4. thread:竞争锁失败的线程
  5. nextWaiter:在条件队列中等待的节点(条件队列是单向链表)

ReentrantLock

内部实现了两种锁:公平锁和非公平锁(默认使用的是非公平锁)

公平锁:当有新的线程尝试获取锁时,如果ReentrantLock的同步队列中已经存在节点,那么直接将线程加入到队列中

非公平锁:当有新的线程尝试获取锁时,不管队列中是否已经有节点,都去参与竞争锁,竞争失败则放入到同步队列中

lock()

lock()是不可中断互斥锁,方法在尝试获取锁的期间,如果线程被中断,也不会响应中断,会一直尝试获取锁

在线程第一次尝试获取锁失败后,并不会立即加入同步队列,会再次尝试获取锁

图解为非公平锁的获取锁流程:

unlock()

unlock()释放锁的流程: 如果是同一个线程多次调用的方法中都去获取了锁,是可以允许的。在释放锁时,调用了多少次就要释放多少次,当锁的状态变为0之后,就会唤醒同步队列中的线程去竞争锁

需要手动调用,所以最好是在try块的finally方法中调用,确保获取锁的次数和释放锁的次数一致。不然队列中的线程就会一致阻塞

trylock()

trylock()只支持非公平锁

        //使用的是非公平锁,在获取锁失败后直接返回false,不会进入同步队列等待
        //需要业务中自己处理获取失败后的备用方案
        public boolean tryLock() {
            return sync.nonfairTryAcquire(1);
        }

        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                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;
        }

tryLock(long timeout, TimeUnit unit)

默认实现的是非公平锁,公平锁在创建ReentrantLock时指定

在线程获取锁的时候,没有超过过期时间,会在同步队列中等待被前驱节点唤醒继续竞争锁。

如果超过了过期时间,线程会退出同步队列不再去竞争锁

如果再次期间线程被中断了,会抛出异常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值