ReentrantLock锁

ReentrantLock可重入锁

1.1 概述

ReentrantLock 实现了 Lock接口,Lock接口中定义了 lockunlock相关操作,并且还存在 newCondition方法,表示生成一个条件。

public class ReentrantLock implements Lock, java.io.Serializable

ReentrantLock是一个可重入锁。

可重入锁 指的是可以再次获取自己的内部锁,一个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其想要再次获取这个对象的锁的时候还是可以获取;如果不可锁重入的话,就会造成死锁。同一个线程每次获取锁,锁的计数器都自增 1,获取多少锁就要释放多少锁,当锁的同步状态为 0 时才能释放锁。

  • 为什么会造成死锁呢?

    该线程本拥有这个对象的锁,当想要再次获得的时候,如果不可重入,那么就会一直等待,程序未执行完成,本身含有的锁也不会解锁,那么也就是无谓的等待,造成死锁。

1.2 代码层面

Reentrantlock 需要手动上锁与解锁,需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成,并且只能在代码块中使用。

public void test () throw Exception {
    ReentrantLock lock = new ReentrantLock();
    try {
    	lock.lock();
    } finally {
         // 需手动释放锁
        lock.unlock();
    }
}
  • ReentrantLock可以指定是公平锁还是非公平锁

    • 公平锁就是某个线程释放锁之后,等待队列中的线程是按FIFO的原则获取锁,即先等待的线程先获得锁

    • 非公平锁即某个线程释放锁之后,等待队列中的线程共同竞争锁,谁先得到锁就是谁的

    • 相对来说,非公平锁会有更好的性能,吞吐量比较大。但非公平锁让线程获取锁的时间变得更加不确定,可能会导致在阻塞队列中的线程长期处于饥饿状态,即迟迟抢不到锁,无法继续进行下去。

  • 公平锁与非公平锁的区别

    1. 非公平锁在调用 lock 后,首先就会调用 CAS 进行一次抢锁,如果这个时候锁没有被占用,那么直接获取到锁返回了
    2. 非公平锁在 CAS 失败后,和公平锁一样都会进入到 tryAcquire 方法,在 tryAcquire 方法中,如果发现锁这个时候被释放了,非公平锁会直接 CAS 抢锁,而公平锁会判断前方是否有线程在等待,如果有,则自动加入队尾
    3. 如果这两次 CAS 都不成功,那么非公平锁和公平锁是一样的,都要进入到阻塞队列等待唤醒。

ReentrantLock默认情况是非公平的,可以通过 ReentrantLock类的构造方法ReentrantLock(boolean fair)来指定是否是公平,true为公平。

1.3 synchronizedReentrantlock 的区别

  1. 共同点:两个都是可重入锁

  2. synchronized依赖于 JVM,Reentrantlock 依赖于API

    • synchronized 底层实现由 JVM 实现上锁与解锁,锁升级过程也由JVM实现;能够修饰方法,运用于代码块和实例方法、静态方法
    • Reentrantlock 需要手动上锁与解锁,需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成,且只能在代码块中使用
  3. ReentrantLocksynchronized 增加了一些功能

    • 等待可中断 : ReentrantLock提供了一种能够中断等待锁的线程的机制,通过 lock.lockInterruptibly() 来实现这个机制,即正在等待的线程可以选择放弃等待,改为处理其他事情

    • 可实现公平锁 : ReentrantLock可以指定是公平锁还是非公平锁,而synchronized只能是非公平锁

    • 可实现选择性通知:

      1、synchronized关键字与wait()notify()/notifyAll()方法相结合可以实现等待/通知机制

      2、ReentrantLock类当然也可以实现,但是需要借助于Condition接口(含await()、signalAll() 、 signa()方法)newCondition()方法。ReentrantLock类结合Condition实例可以实现“选择性通知”:线程对象可在指定的Condition实例中注册,进行有选择性的线程通知。可以把多个Condition实例理解为一个个小组,小组内的信息只通知该小组内的线程。

      3、synchronized关键字就相当于整个 Lock 对象中只有一个Condition实例,所有的线程都注册在它一个身上。如果执行notifyAll()方法的话就会通知所有处于等待状态的线程,这样会造成很大的效率问题,而Condition实例的signalAll()方法 只会唤醒注册在该Condition实例中的所有等待线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值