【Java多线程】ReentrantLock

本文介绍了Java中的ReentrantLock,作为锁的一种工具,提供了比Synchronized更灵活的操作。ReentrantLock支持公平锁和非公平锁,允许线程中断获取锁,并提供了读写锁以提高并发性能。文章通过分析lockInterruptibly()方法和Condition的使用,展示了如何避免死锁和实现线程通信,并探讨了ReentrantLock的实现原理。
摘要由CSDN通过智能技术生成

ReentrantLock

在实现线程同步时,大多情况下使用的是Synchronized关键字实现,但是Synchronized的锁太过封闭,获得锁和释放锁都是系统自动的。所以为了更灵活的操作,在JDK1.5版本之后,就诞生了Lock接口以及其实现类。

lock接口也是对资源上锁的一种工具,它不同于Synchronized的隐式上锁与解锁,lock接口中的获取锁和释放锁,是需要手动去操作的。

Synchronized关键字的同步代码出现以下三种情况才会释放锁:

  • 1、同步代码块执行完成,自动释放锁。
  • 2、同步代码块出现异常或者错误,此时释放锁。
  • 3、当前获得锁的线程状态置为Waiting或者Time_Waitiing,此时释放锁。(置为Waitiing也就是对象锁调用了wait()方法,或者 lock对象对应的condition对象中的await()方法)。

Synchronized的缺陷:

  • 缺点1:多个线程去获取锁资源,只有一个线程可以获得锁,其他线程只能阻塞,什么事情都做不了。因此,需要一种机制让处于阻塞的线程可以中断对锁的获取,也就是抛弃某些线程。(解决方案:Lock接口中的lockInterruptibly(),或者trylock(long time,TimeUnit unit))。
  • 缺点2:当文件被读写时,读操作和写操作同样要获取当前文件的锁资源,Synchronized有且仅有一个线程访问当前文件并进行读或者写。此时效率会低下。因此,需要一种机制来使得当多个线程都只是进行读操作时,线程之间不会发生冲突。(解决方案:ReadWriteLock接口实现类:ReentrantReadWtriteLock)。
  • 缺点3:我们无法得知当前线程是否获得了锁。因此我们需要一个方法来查看当前锁是否获取到了。(解决方案 : Lock接口中的tryLock())。

Lock中的方法

lock(); //获取锁

unlock(); //释放锁

trylock(); //尝试获取锁,获取到了返回true,获取不到返回false; 可轮询

trylock(long time ,TimeUnit unit); // 在一定时间内获取锁,获取到了返回true,获取不到返回false;可定时的

lockInterruptibly(); //获取锁,但是可以被中断 可响应中断
    //具体意思就是这个方法和lock是一样的,
    //都是获取锁的方法,但是它可以被interrupt中断,中断了获取锁的状态,
    //就好比直接将当前线程抛弃。

Condition  newCondition(); //生成一个Condition,可以对锁对象的进行等待,唤醒等操作,也就是用于线程通信
  • ReentrantLock使用格式:
Lock lock = new ReentrantLo
lock.lock();//加锁
try{
   
    //共享代码
}catch{
   

}finally{
   
    lock.unlock(); //释放锁
}
public class TestDemo {
   
    private static final Lock lock = new ReentrantLock();
    public static void main(String[] args) {
   
        lock.lock();
        try{
   
            System.out.println(Thread.currentThread().getName()+" got the lock");
        }finally {
   
            System.out.println(Thread.currentThread().getName()+" release the lock");
            lock.unlock();
        }
    }
}

ReentrantLock释放锁是显式的,有可能会忘记清除锁,使用起来更加"危险"。

ReentrantLock是Lock接口的唯一实现子类。

ReentrantLock是一个可重入锁。什么叫做可重入锁呢,就是当前线程中的方法对锁资源进行获取之后,方法内部中还有一个线程对锁进行获取,此时就不需要再获取锁了,直接进入。这就是可重入锁。Synchronized也是可重入锁,在讲解monitor中就可以看出。

ReentrantLock的实现方式

ReentrantLock主要利用CAS+CLH队列来实现。它支持公平锁和非公平锁,两者的实现类似。

  • 非公平锁:随机的获取,谁运气好,谁先获得cpu使用权,哪个线程就先获取执行。
  • 公平锁:第一次获取锁的线程,在下一次执行也会优先获取锁。
public ReentrantLock()//无参构造函数 -> 非公平锁
public ReentrantLock(boolean fair)//true表示公平锁,false表示非公平锁
public class TestDemo {
   
    private static final Lock lock = new ReentrantLock(true); //公平锁
    public static void test(){
   
        for(int i=0; i<3; i++){
   
           lock.lock();
           try {
   
               System.out.println(Thread.currentThread().getName()+" got the lock");
               TimeUnit.
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值