Java显式锁-读写锁

简介: ReentrantLock 实现了标准的互斥锁,每次最多只有一个线程持有 ReentrantLock ,从数据的完整性来看互斥是一种强硬的加锁规则

@TOC

一、ReentrantLock 简介

ReentrantLock实现了Lock接口,并提供了和synchronized相同的互斥性和内存可见性以及可重入的加锁语义。和synchronized相比它再处理锁的不可用性上有更高的灵活性。

下面摘自JDK11文档:

ReentrantLock是一个可重入互斥锁,其基本行为和语义与使用同步方法和语句访问的隐式监视器锁相同,但具有扩展功能。
ReentrantLock由上次成功锁定但尚未解锁的线程所有。当该锁不属于另一个线程时,调用锁的线程将返回并成功获取该锁。如果当前线程已经拥有锁,则该方法将立即返回。这可以使用方法isHeldByCurrentThread和getHoldCount进行检查。
此类的构造函数接受一个可选的公平性参数。当设置为true时,在争用下,锁定有利于授予对等待时间最长的线程的访问权限。否则,此锁不能保证任何特定的访问顺序。使用许多线程访问的公平锁的程序可能显示出比使用默认设置的程序更低的总体吞吐量(即,更慢;通常慢得多),但变化较小。

二、ReentrantLock 和 synchronized 如何选择

2.1 ReentrantLock 优缺

ReentrantLock 和 synchronized 除了在内存和加锁语义上相同之外,ReentrantLock 还提供了定时的锁等待、可中断的锁等待、公平性、以及实现非块结构的加锁。在性能上ReentrantLock 稍优于synchronized 。但 ReentrantLock 的危险性更高,如果在 finally中忘记释放它,程序仍就能继续运行,但是这是一个大炸弹

2.2 synchronized 优缺

synchronized 是大家都熟悉的一种锁,它简洁紧凑并且在线程转储中能给出在那些调用帧中获得了那些锁,也能检测和识别发生生死锁的线程。与之相比的 ReentrantLock 锁的非块结构决定了它无法确定那些调用帧中获得了那些锁🤣

2.3 结论

除非明确需要ReentrantLock 包含的伸缩性,否则还是 synchronized 更香。

三、读写锁

3.1 简要介绍

ReentrantLock 实现了标准的互斥锁,每次最多只有一个线程持有 ReentrantLock ,从数据的完整性来看互斥是一种强硬的加锁规则。因此很自然的并发就不要想了~

互斥避免了 写/写 冲突,写/读 冲突,但也造成了 读/读冲突😂,有得有失吧。但是吧,大部分情况下我们都在读读。

所以读写锁一般在一个资源被多个读或者多个写访问的时候使用,这两者不能同时存在。

3.2 ReadWriteLock

ReadWriteLock 暴露了两个 Lock 对象,一个是读,一个是写。这两个锁看起来是相互独立的,但是它们只是读-写锁对象的不同视图。

public interface ReadWriteLock {
   
    /**
     * 返回用于读取的锁。
     *
     * @return 用于阅读的锁
     */
    Lock readLock();

    /**
     * 返回用于写的锁。
     *
     * @return 用于写的锁。
     */
    Lock writeLock();
}

3.3 实现

ReadWriteLock 可以采用多种不同的实现方式,但同样的它们的性能、优先性、调度、公平性等方面也会不同。

读写锁是一种性能优化措施,在特定的情况下能实现更高的并发性。而在频繁读取的场景下,读写锁可以提高性能。但在其它情况下读写锁比独占锁要差一些,这是因为它们的复杂性更高。

读写锁有多种实现方式,其中都需要考虑以下几点:

  • 释放有限
    当一个写入操作释放写入锁时,并且队列中同时存在读线程和写线程,那么应该优先选择读线程,写线程,还是最先发出请求的线程?
  • 读线程插队
    如果锁是由读线程持有,但有写线程正在等待,那么新到达的读线程能否立即获得访问权,还是应该在写线程后面等待?如果允许读线程插队到写线程之前,那么将提高并发性,但却可能造成写线程发生饥饿问题。
  • 重入性
    读取锁和写人锁是否是可重入的?
  • 降级
    如果一个线程持有写人锁,那么它能否在不释放该锁的情况下获得读取锁? 这可能会使得写人锁被“降级”为读取锁,同时不允许其他写线程修改被保护的资源。
  • 升级
    读取锁能否优先于其他正在等待的读线程和写线程而升级为一个写入锁?在大多数的读一 写锁实现中并不支持升级,因为如果没有显式的升级操作,那么很容易造成死锁。(如果两个读线程试图同时升级为写人锁,那么二者都不会释放读取锁。)

说了这么多,我们举个例子看看:

/**
 * Auth lhd
 * Date 2023/8/3 10:00
 * Annotate
 */
public class ReadwriteMape<K,V> {
   
    private final Map<K,V> map;
    private final ReadwriteLock lock = new ReentrantReadWriteLock() ;
    private final Lock r = lock.readloek();
    private final Lock w = lock.writeLock() ;
    public ReadWriteMap(MapeK,V map){
   
        this .map = map;
    }

    public V put(K key, V value) {
   
        W.lock();
        try {
   
            return map.put (key, value) ;
        }finally {
   
            w.unlock();
        }
    }
    // 对 romove(],putA11(),clear()等方法执行相同的操作
    public V get (Object key){
   
        r.lock();
        try {
   
            return map.get(key);
        }finally {
   
            r.unlock();
        }
    }
    //对其他只读的 Map 方法执行相同的操作

}
目录
相关文章
|
2月前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
44 2
|
10天前
|
缓存 Java
java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁
本文介绍了几种常见的锁机制,包括公平锁与非公平锁、可重入锁与不可重入锁、自旋锁以及读写锁和互斥锁。公平锁按申请顺序分配锁,而非公平锁允许插队。可重入锁允许线程多次获取同一锁,避免死锁。自旋锁通过循环尝试获取锁,减少上下文切换开销。读写锁区分读锁和写锁,提高并发性能。文章还提供了相关代码示例,帮助理解这些锁的实现和使用场景。
java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁
|
1月前
|
Java
Java 中锁的主要类型
【10月更文挑战第10天】
|
1月前
|
XML JavaScript Java
java与XML文件的读写
java与XML文件的读写
25 3
|
2月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
2月前
|
算法 Java 关系型数据库
Java中到底有哪些锁
【9月更文挑战第24天】在Java中,锁主要分为乐观锁与悲观锁、自旋锁与自适应自旋锁、公平锁与非公平锁、可重入锁以及独享锁与共享锁。乐观锁适用于读多写少场景,通过版本号或CAS算法实现;悲观锁适用于写多读少场景,通过加锁保证数据一致性。自旋锁与自适应自旋锁通过循环等待减少线程挂起和恢复的开销,适用于锁持有时间短的场景。公平锁按请求顺序获取锁,适合等待敏感场景;非公平锁性能更高,适合频繁加解锁场景。可重入锁支持同一线程多次获取,避免死锁;独享锁与共享锁分别用于独占和并发读场景。
|
1月前
|
安全 Java 开发者
java的synchronized有几种加锁方式
Java的 `synchronized`通过上述三种加锁方式,为开发者提供了从粗粒度到细粒度的并发控制能力,满足了不同场景下的线程安全需求。合理选择加锁方式对于提升程序的并发性能和正确性至关重要,开发者应根据实际应用场景的特性和性能要求来决定使用哪种加锁策略。
16 0
|
1月前
|
Java 应用服务中间件 测试技术
Java21虚拟线程:我的锁去哪儿了?
【10月更文挑战第8天】
32 0
|
2月前
|
Java 数据库
JAVA并发编程-一文看懂全部锁机制
曾几何时,面试官问:java都有哪些锁?小白,一脸无辜:用过的有synchronized,其他不清楚。面试官:回去等通知! 今天我们庖丁解牛说说,各种锁有什么区别、什么场景可以用,通俗直白的分析,让小白再也不怕面试官八股文拷打。
|
2月前
|
安全 Java 开发者
Java并发编程中的锁机制解析
本文深入探讨了Java中用于管理多线程同步的关键工具——锁机制。通过分析synchronized关键字和ReentrantLock类等核心概念,揭示了它们在构建线程安全应用中的重要性。同时,文章还讨论了锁机制的高级特性,如公平性、类锁和对象锁的区别,以及锁的优化技术如锁粗化和锁消除。此外,指出了在高并发环境下锁竞争可能导致的问题,并提出了减少锁持有时间和使用无锁编程等策略来优化性能的建议。最后,强调了理解和正确使用Java锁机制对于开发高效、可靠并发应用程序的重要性。
28 3