Java并发编程之显示锁ReentrantLock和ReadWriteLock读写锁

作者:junjie 时间:2023-06-04 04:54:22 

在Java5.0之前,只有synchronized(内置锁)和volatile. Java5.0后引入了显示锁ReentrantLock.

ReentrantLock概况

ReentrantLock是可重入的锁,它不同于内置锁, 它在每次使用都需要显示的加锁和解锁, 而且提供了更高级的特性:公平锁, 定时锁, 有条件锁, 可轮询锁, 可中断锁. 可以有效避免死锁的活跃性问题.ReentrantLock实现了

Lock接口:


  public interface Lock {
          //阻塞直到获得锁或者中断
          void lock();

          //阻塞直到获得锁或者中断抛异常
          void lockInterruptibly() throws InterruptedException;

          //只有锁可用时才获得,否则直接返回
          boolean tryLock();

          //只有锁在指定时间内可用时才获得,否则直接返回,中断时抛异常
          boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

          void unlock();

          //返回一个绑定在这个锁上的条件
          Condition newCondition();
  }

Lock使用


        Lock lock = new ReentrantLock();
        lock.lock();
        try{
            //更新对象状态
        }finally{
            //这里注意,一定要有finally代码块去解锁
            //否则容易造成死锁等活跃性问题
            lock.unlock();
        }
 


ReentrantLock特性

轮询锁的和定时锁

可轮询和可定时的锁请求是通过tryLock()方法实现的,和无条件获取锁不一样. ReentrantLock可以有灵活的容错机制.死锁的很多情况是由于顺序锁引起的, 不同线程在试图获得锁的时候阻塞,并且不释放自己已经持有的锁, 最后造成死锁. tryLock()方法在试图获得锁的时候,如果该锁已经被其它线程持有,则按照设置方式立刻返回,而不是一直阻塞等下去,同时在返回后释放自己持有的锁.可以根据返回的结果进行重试或者取消,进而避免死锁的发生.

公平性

ReentrantLock构造函数中提供公平性锁和非公平锁(默认)两种选择。所谓公平锁,线程将按照他们发出请求的顺序来获取锁,不允许插队;但在非公平锁上,则允许插队:当一个线程发生获取锁的请求的时刻,如果这个锁是可用的,那这个线程将跳过所在队列里等待线程并获得锁。我们一般希望所有锁是非公平的。因为当执行加锁操作时,公平性将讲由于线程挂起和恢复线程时开销而极大的降低性能。考虑这么一种情况:A线程持有锁,B线程请求这个锁,因此B线程被挂起;A线程释放这个锁时,B线程将被唤醒,因此再次尝试获取锁;与此同时,C线程也请求获取这个锁,那么C线程很可能在B线程被完全唤醒之前获得、使用以及释放这个锁。这是种双赢的局面,B获取锁的时刻(B被唤醒后才能获取锁)并没有推迟,C更早地获取了锁,并且吞吐量也获得了提高。在大多数情况下,非公平锁的性能要高于公平锁的性能。

可中断获锁获取操作

lockInterruptibly方法能够在获取锁的同时保持对中断的响应,因此无需创建其它类型的不可中断阻塞操作。

读写锁ReadWriteLock

ReentrantLock是一种标准的互斥锁,每次最多只有一个线程能持有锁。读写锁不一样,暴露了两个Lock对象,其中一个用于读操作,而另外一个用于写操作。


public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading.
     */
    Lock readLock();

    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing.
     */
    Lock writeLock();
}

可选择实现:

1.释放优先
2.读线程插队
3.重入性
4.降级
5.升级

ReentrantReadWriteLock实现了ReadWriteLock接口,构造器提供了公平锁和非公平锁两种创建方式。读写锁适用于读多写少的情况,可以实现更好的并发性。
 
示例


public class ReadWriteMap<K, V> {
    private Map<K, V> map;
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    private final Lock readLock = lock.readLock();
    private final Lock writeLock = lock.writeLock();

    public ReadWriteMap(Map<K, V> map) {
        this.map = map;
    }

    public V get(K key) {
        readLock.lock();
        try {
            return map.get(key);
        } finally {
            readLock.unlock();
        }
    }

    public void put(K key, V value) {
        writeLock.lock();
        try {
            map.put(key, value);
        } finally {
            writeLock.unlock();
        }
    }
}

标签:Java,并发编程,显示锁,ReentrantLock,ReadWriteLock,读写锁
0
投稿

猜你喜欢

  • 两分钟解决IntelliJ IDEA中文乱码问题(推荐)

    2022-11-09 00:08:15
  • Java基础之容器Vector详解

    2023-11-25 13:10:07
  • Java超详细教你写一个银行存款系统案例

    2022-01-04 22:33:59
  • java实现gif动画效果(java显示动态图片)

    2023-10-19 07:56:38
  • java调用openoffice将office系列文档转换为PDF的示例方法

    2023-11-29 11:42:53
  • 全面了解Java中的内部类和匿名类

    2023-01-05 09:14:23
  • 关于C#调用C++dll传指针释放内存问题

    2021-12-20 06:56:34
  • Android解析XML文件升级APK的方法

    2022-06-05 20:47:26
  • Java基础之详解HashSet的使用方法

    2023-08-04 20:18:59
  • jpa EntityManager 复杂查询实例

    2023-08-31 01:03:01
  • 关于C++运算符重载的一些困惑详解

    2023-05-25 15:33:20
  • Java+Swing实现五子棋游戏的示例代码

    2022-06-27 11:56:22
  • C# 中用 Sqlparameter 的两种用法

    2022-11-19 03:52:52
  • 基于JDK动态代理原理解析

    2022-07-24 19:43:33
  • windows定时器配置执行java jar文件的方法详解

    2023-04-17 16:40:21
  • C# 调用C++写的dll的实现方法

    2022-10-25 11:36:56
  • SpringBoot统一处理功能实现的全过程

    2022-12-24 09:43:26
  • 深入解析Java的设计模式编程中的模板方法模式

    2023-11-01 13:31:14
  • Eclipse代码格式化设置简单介绍

    2023-10-26 21:59:31
  • viewpager+photoview实现图片查看器

    2022-10-30 11:46:05
  • asp之家 软件编程 m.aspxhome.com