ReentrantLock详解


前言

在Java的并发编程库中,ReentrantLock是一种非常重要的同步工具,它提供了一种比内置synchronized关键字更加灵活和可定制的锁定机制。在本文中,我们将详细讨论ReentrantLock的工作原理、特性以及如何使用它来解决多线程并发问题。

一、概述

ReentrantLock 实现了 Lock 接口,是一个可重入且独占式的锁,和 synchronized 关键字类似。不过,ReentrantLock 更灵活、更强大,增加了轮询、超时、中断、公平锁和非公平锁等高级功能。

二、重要特性

  1. 轮询: ReentrantLock提供了tryLock()方法获取锁,和synchronized关键字不一样,这是非阻塞式的。如果锁当前不可用,则方法会立即返回,并且不会导致调用线程阻塞。
  2. 可重入性: 可重入锁 也叫递归锁,指的是线程可以再次获取自己的内部锁。比如一个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果是不可重入锁的话,就会造成死锁。
  3. 超时: reentrant Lock提供了tryLock(long timeout,TimeUnit unit)方法可以指定获取锁的等待时间。如果在指定时间范围内获取到了锁,那么方法返回true,反之返回false。之后正常执行后续代码。
  4. 中断: ReentrantLock提供了一种能够中断等待锁的线程的机制,通过 lock.lockInterruptibly() 来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。
  5. 公平锁: ReentrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。ReentrantLock默认情况是非公平的,可以通过 ReentrantLock类的ReentrantLock(boolean fair)构造方法来指定是否是公平的。

公平锁因为比非公平锁多了额外的判断逻辑,需要让先等待的线程先获得锁,所以公平锁的性能不如非公平锁。但是非公平锁让获取锁的线程具有随机性,因此可能导致某些线程一直获取不到锁,导致饥饿。在实际开发中,要根据实际情况进行选择。

三、ReentrantLock和Synchronized比较

ReentrantLock 和 synchronized 都是 Java 中用于实现线程同步的机制,它们具有共同的目标——确保多线程环境下的数据一致性,防止并发访问导致的数据不一致问题。下面是它们的一些相同点和不同点的总结:

3.1、相同点

  1. 功能目标: 两者都用于实现线程间的互斥,即一次只允许一个线程访问临界区(共享资源)。
  2. 可重入性: 它们都支持可重入特性,这意味着已经拥有锁的线程可以再次获取同一把锁而不陷入死锁。

3.1、不同点

  1. 使用方式: synchronized 可以用于修饰方法(实例方法、静态方法)、代码块,而 ReentrantLock 只能用于代码块,需要显式调用 lock() 和 unlock() 方法。
  2. 公平锁和非公平锁: synchronized 默认是非公平锁,不支持配置为公平锁。ReentrantLock 支持选择公平锁或非公平锁,可以通过构造函数传入参数来指定。
    中断响应:
  3. 等待可中断性: synchronized 在等待锁的过程中无法响应中断,即使线程被中断,它仍然会等待锁的释放。ReentrantLock 提供了 lockInterruptibly() 方法,使得等待锁的线程可以响应中断,从而提前退出等待。
  4. 绑定条件变量: ReentrantLock 提供了 Condition 对象,可以实现更细粒度的线程通知和等待,而 synchronized 只能使用 wait() 和 notify() 或 notifyAll() 方法,这些方法作用于整个锁。
  5. 底层实现: synchronized 是 JVM 层面的同步机制,依赖于 JVM 的监视器锁(Monitor)实现。ReentrantLock 是基于 Java 类库实现的,具体来说,它使用了抽象队列同步器(AbstractQueuedSynchronizer, AQS)框架。

四、ReentrantLock的使用

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class test {
    public static void main(String[] args) throws InterruptedException {

        ReentrantLock lock = new ReentrantLock(true);//通过true设置为公平锁

        int num=1;
        //尝试获取锁
        try{
            lock.tryLock();
            num+=1;
        }finally {
            //需要在finally代码块中手动释放,不然锁会被一直占用
            lock.unlock();
        }
        try {
            //指定获取锁的等待时间
            //该方法成功获取到锁会返回true,没获取到返回false。
            if (lock.tryLock(200, TimeUnit.SECONDS)){
                num+=2;
            }else{
                System.out.println("在指定等待时间内未获取到锁");
            }
        }finally {
            lock.unlock();
        }
    }

}

总结

ReentrantLock 是 Java 提供的一种可重入的互斥锁,它具有与 synchronized 关键字类似的同步和锁定能力,比 synchronized 更灵活,但是使用更复杂。ReentrantLock支持中断获取锁、尝试获取锁(限时/非限时)和可轮询的获取锁等特性,适用于需要更高级锁定控制的场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值