读写锁

【Java并发工具类】ReadWriteLock

房东的猫 提交于 2020-02-19 17:55:16
摘自: https://www.cnblogs.com/myworld7/p/12323467.html 阅读目录 前言 什么是读写锁 ReentrantReadWriteLock 实现一个快速缓存 缓存数据的初始化 实现缓存的按需加载 读写锁的升级与降级 小结 回到目录 前言 前面介绍过 ReentrantLock ,它实现的是一种标准的互斥锁:每次最多只有一个线程能持有ReentrantLock。这是一种强硬的加锁规则,在某些场景下会限制并发性导致不必要的抑制性能。互斥是一种保守的加锁策略,虽然可以避免“写/写”冲突和“写/读”冲突,但是同样也避免了“读/读”冲突。 在读多写少的情况下,如果能够放宽加锁需求,允许多个执行读操作的线程同时访问数据结构,那么将提升程序的性能。只要每个线程都能确保读到最新的数据,并且在读取数据时不会有其他的线程修改数据,那么就不会发生问题。在这种情况下,就可以使用 读写锁 :一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行。 Java中读写锁的实现是 ReadWriteLock 。下面我们先介绍什么是读写锁,然后利用读写锁快速实现一个缓存,最后我们再来介绍读写锁的升级与降级。 回到目录 什么是读写锁 读写锁是一种性能优化措施,在读多写少场景下,能实现更高的并发性。读写锁的实现需要遵循以下三项基本原则: 允许多个线程同时读共享变量

深入并发锁,解析Synchronized锁升级

六月ゝ 毕业季﹏ 提交于 2020-02-09 17:06:40
这篇文章分为六个部分,不同特性的锁分类,并发锁的不同设计,Synchronized中的锁升级,ReentrantLock和ReadWriteLock的应用,帮助你梳理 Java 并发锁及相关的操作。 一、锁有哪些分类 一般我们提到的锁有以下这些: 乐观锁/悲观锁 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 分段锁 偏向锁/轻量级锁/重量级锁 自旋锁 上面是很多锁的名词,这些分类并不是全是指锁的状态,有的指锁的特性,有的指锁的设计,下面分别说明。 1、乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度,在Java和数据库中都有此概念对应的实际应用。 (1)乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。 乐观锁适用于多读的应用类型,乐观锁在Java中是通过使用无锁编程来实现,最常采用的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。 CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步。java.util.concurrent包中的原子类就是通过CAS来实现了乐观锁。 简单来说,CAS算法有3个三个操作数:

简单看看读写锁ReentantReadWriteLock

三世轮回 提交于 2020-02-06 19:49:12
  前面我们看了可重入锁ReentrantLock,其实这个锁只适用于写多读少的情况,就是多个线程去修改一个数据的时候,适合用这个锁,但是如果多个线程都去读一个数据,还用这个锁的话会降低效率,因为同一时刻只能是一个线程去读取!   本次我们看看读写锁ReentantReadWriteLock,这个锁采用了读写分离的策略,分成了读锁和写锁,多个线程可以同时获取读锁; 一.简单使用读写锁   啥也别问,问就是先会用了再说,还记得前面用ReentrantLock实现了一个线程安全的List吗?我们可以使用读写锁稍微改造一下就好了; package com.example.demo.study; import java.util.ArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class Study0204 { // 线程不安全的List private ArrayList<String> list = new ArrayList<String>(); // 读写锁 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock()

【JUC】JDK1.8源码分析之ReentrantReadWriteLock

喜欢而已 提交于 2020-01-25 22:14:52
重入锁 ReentrantLock是排他锁 ,排他锁在同一时刻仅有一个线程可以进行访问,但是在大多数场景下,大部分时间都是提供读服务,而写服务占有的时间较少。然而读服务不存在数据竞争问题,如果 一个线程在读时禁止其他线程读势必会导致性能降低 。所以就提供了读写锁。 读写锁维护着一对锁,一个读锁和一个写锁,读锁是共享锁,写锁是独占锁 。通过分离读锁和写锁,使得 并发性比一般的排他锁有了较大的提升 :在同一时间可以允许多个读线程同时访问,但是在写线程访问时,所有读线程和写线程都会被阻塞。 读写锁的主要特性: 公平性:支持公平性和非公平性。 重入性:支持重入。读写锁最多支持65535个递归写入锁和65535个递归读取锁。 锁降级:遵循获取写锁、获取读锁在释放写锁的次序,写锁能够降级成为读锁 读写锁ReentrantReadWriteLock实现接口ReadWriteLock,该接口维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。 public interface ReadWriteLock { Lock readLock(); Lock writeLock(); } ReadWriteLock定义了两个方法。readLock()返回用于读操作的锁,writeLock()返回用于写操作的锁

读写锁--ReentrantReadWriteLock

房东的猫 提交于 2020-01-25 22:13:42
  读写锁,对于读操作来说是共享锁,对于写操作来说是排他锁,两种操作都可重入的一种锁。底层也是用AQS来实现的,我们来看一下它的结构跟代码: -----------------------------------------------------------------------------------------------   读写锁,当然要区分读跟写两种操作,因此其内部有ReadLock跟WriteLock两种具体实现。但两者也有交互的地方,比如获取写锁要判断当前是否有线程在读,有的话就需要等待,因此内部是使用的同一个队列同步器。因为获取锁的时候,支持公平与非公平两种方式,故而同步器的包装类Sync也有两个:FairSync跟NonfairSync。 从写锁的获取开始: protected final boolean tryAcquire(int acquires) { Thread current = Thread.currentThread(); int c = getState(); // 重入锁的计数 int w = exclusiveCount(c); // 计数高低位拆开为读计数跟写计数,计算写计数 if (c != 0) { // 有人在占有锁 if (w == 0 || current != getExclusiveOwnerThread()) //

并发编程之读写锁特性及ReentrantReadWriteLock的使用

谁说胖子不能爱 提交于 2020-01-23 19:36:59
读写锁特性: 多个线程的操作中,写写互斥、读写互斥、读读共享 新建一个ReetrantReadWriteLock的类,一个输出的方法,一个变量自增的方法,模拟三个线程,看输出结果: package com . cljtest . demo . mylock ; public class ReentrantReadWriteLockDemo { private int i = 0 ; private int j = 0 ; public void out ( ) { System . out . println ( Thread . currentThread ( ) . getName ( ) + "i的值为----->" + i + "--j的值为----->" + j ) ; } public void inCreate ( ) { i ++ ; try { Thread . sleep ( 1000 L ) ; } catch ( InterruptedException e ) { e . printStackTrace ( ) ; } j ++ ; } public static void main ( String [ ] args ) { ReentrantReadWriteLockDemo readWriteLockDemo = new

让C#轻松实现读写锁分离

柔情痞子 提交于 2020-01-21 16:14:26
ReaderWriterLockSlim 类 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问。 使用 ReaderWriterLockSlim 来保护由多个线程读取但每次只采用一个线程写入的资源。 ReaderWriterLockSlim 允许多个线程均处于读取模式,允许一个线程处于写入模式并独占锁定状态,同时还允许一个具有读取权限的线程处于可升级的读取模式,在此模式下线程无需放弃对资源的读取权限即可升级为写入模式。 注意 ReaderWriterLockSlim 类似于 ReaderWriterLock,只是简化了递归、升级和降级锁定状态的规则。 ReaderWriterLockSlim 可避免多种潜在的死锁情况。 此外,ReaderWriterLockSlim 的性能明显优于 ReaderWriterLock。 建议在所有新的开发工作中使用 ReaderWriterLockSlim。 以上引用自MSDN ps:该类在.NET3.5中提供,如需要在2.0中使用请换ReaderWriterLock,用法差不多改了写方法名,MSDN中说ReaderWriterLockSlim性能比较高 主要属性,方法 属性: IsReadLockHeld   获取一个值,该值指示当前线程是否已进入读取模式的锁定状态。 IsWriteLockHeld   获取一个值

C++多线程-读写锁

こ雲淡風輕ζ 提交于 2020-01-21 05:38:18
在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢? 有,那就是读写锁。 (1)首先,我们定义一下基本的数据结构。 typedef struct _RWLock { int count ; int state ; HANDLE hRead ; HANDLE hWrite ; } RWLock ; 同时,为了判断当前的锁是处于读状态,还是写状态,我们要定义一个枚举量, typedef enum { STATE_EMPTY = 0 , STATE_READ , STATE_WRITE } ; (2)初始化数据结构 RWLock * create_read_write_lock ( HANDLE hRead , HANDLE hWrite ) { RWLock * pRwLock = NULL ; assert ( NULL != hRead && NULL != hWrite ) ; pRwLock = ( RWLock * ) malloc ( sizeof ( RWLock ) ) ; pRwLock - > hRead = hRead ; pRwLock -

Java并发--读写锁的实现分析

◇◆丶佛笑我妖孽 提交于 2020-01-20 20:50:45
读写状态的设计 读写锁同样依赖自定义同步器来实现同步功能,而读写状态就是其同步器的同步状态。回想ReentrantLock中自定义同步器的实现,同步状态表示锁被一个线程重复获取的次数,而读写锁的自定义同步器需要在同步状态(一个整型变量)上维护多个读线程和一个写线程的状态,使得该状态的设计成为读写锁实现的关键。 如果在一个整型变量上维护多种状态,就一定需要“按位切割使用”这个变量,读写锁将变量切分成了两个部分,高16位表示读,低16位表示写,划分方式如下图所示。 当前同步状态表示一个线程已经获取了写锁,且重进入了两次,同时也连续获取了两次读锁。读写锁是如何迅速确定读和写各自的状态呢?答案是通过位运算。假设当前同步状态值为S,写状态等于S&0x0000FFFF(将高16位全部抹去),读状态等于S>>>16(无符号补0右移16位)。当写状态增加1时,等于S+1,当读状态增加1时,等于S+(1<<16),也就是S+0x00010000。 根据状态的划分能得出一个推论: S不等于0时,当写状态(S&0x0000FFFF)等于0时,则读状态(S>>>16)大于0,即读锁已被获取。 写锁的获取与释放 写锁是一个支持重进入的排它锁。如果当前线程已经获取了写锁,则增加写状态。如果当前线程在获取写锁时,读锁已经被获取(读状态不为0)或者该线程不是已经获取写锁的线程,则当前线程进入等待状态

全面了解Java中的15种锁概念及机制!

半世苍凉 提交于 2020-01-15 17:35:28
在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类。介绍的内容如下: 1.公平锁 / 非公平锁 2.可重入锁 / 不可重入锁 3.独享锁 / 共享锁 4.互斥锁 / 读写锁 5.乐观锁 / 悲观锁 6.分段锁 7.偏向锁 / 轻量级锁 / 重量级锁 8.自旋锁 上面是很多锁的名词,这些分类并不是全是指锁的状态,有的指锁的特性,有的指锁的设计,下面总结的内容是对每个锁的名词进行一定的解释。 公平锁/非公平锁 公平锁 公平锁是指多个线程按照申请锁的顺序来获取锁。 非公平锁 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。 对于 Java ReentrantLock 而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。非公平锁的优点在于吞吐量比公平锁大。 对于 Synchronized 而言,也是一种非公平锁。由于其并不像 ReentrantLock 是通过 AQS 的来实现线程调度,所以并没有任何办法使其变成公平锁。 可重入锁/不可重入锁 可重入锁 广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。 ReentrantLock 和 synchronized