目录

  • 前言
  • `ReadWriteLock` 接口简介及源码
  • `ReetrantReadWriteLock` 类
    • 获取顺序
      • 非公平模式(默认)
      • 公平模式
    • 支持 `Condition`
  • `ReentrantReadWriteLock` 源码
    • `ReentrantReadWriteLock` 主要源码
    • `ReentrantReadWriteLock` 获取读锁或写锁的方法
    • `ReentrantReadWriteLock` 获取与释放锁
      • 读锁的获取
      • 读锁的释放
      • 写锁的获取
      • 写锁的释放
  • `ReetrantReadWriteLock` 使用场景

前言

在没有读写锁之前,ReentrantLockSynchronized 虽然可以保证线程安全,但是也浪费了一定的资源

  • 因为如果多个读操作同时进行,其实并没有线程安全问题,可以允许让多个读操作并行,以便提高程序效率
  • 但是写操作不是线程安全的,如果多个线程同时写,或者在写的同时进行读操作,便会造成线程安全问题

我们的 ReadWriteLock 接口就解决了这样的问题,它设定了一套规则,既可以保证多个线程同时读的效率,同时又可以保证有写入操作时的线程安全

整体思路是它有两把锁:一把锁是写锁,获得写锁之后,既可以读数据又可以修改数据,而另一把锁是读锁,获得读锁之后,只能查看数据,不能修改数据。读锁可以被多个线程同时持有,所以多个线程可以同时查看数据。在读的地方合理使用读锁,在写的地方合理使用写锁,灵活控制,可以提高程序的执行效率

ReadWriteLock 接口简介及源码

ReadWriteLockjava.util.concurrent.locks 包下的接口。ReadWriteLock 管理一组锁,一个是读锁,一个是写锁

  • 读锁是共享的
  • 写锁是独占的
  • 理论上,读写锁比互斥锁( SynchronizedReentrantLock )有更好的性能体现
public interface ReadWriteLock {Lock readLock();Lock writeLock();
}

所有 ReadWriteLock 接口的实现类必须保证内存同步效果:所有写锁 writeLock 的相关操作都对只读锁 readLock 可见。也就是说,如果一个线程成功的获取了只读锁 readLock,那么这个线程可以看到上个写锁 writeLock 所做的所有修改

ReetrantReadWriteLock

ReentrantReadWriteLock 被称为读写锁,它是 ReadWriteLock 接口的实现

获取顺序

这个类不会强行指定访问锁的读写顺序,但是它支持一个可选的公平策略

非公平模式(默认)

当以非公平模式初始化时,读锁和写锁的获取的顺序是不确定的。非公平锁主张竞争获取,可能会延缓一个或多个读或写线程,但是会比公平锁有更高的吞吐量

公平模式

  • 当以公平模式初始化时,线程将会以队列的顺序获取锁。当前线程释放锁后,等待时间最长的写锁线程就会被分配写锁;或者有一组读线程组等待时间比写线程长,那么这组读线程组将会被分配读锁
  • 当有写线程持有写锁或者有等待的写线程时,一个尝试获取公平的读锁(非重入)的线程就会阻塞。这个线程直到等待时间最长的写锁获得锁后并释放掉锁后才能获取到读锁

支持 Condition

就像 ReentrantLock 一样,写锁支持 Condition 操作。当然,这种 Condition 操作,只能被应用在写锁上。读锁不支持 Condition 操作,readLock().newCondition() 会抛出一个 UnsupportedOperationException 异常

ReentrantReadWriteLock 源码

ReentrantReadWriteLock 主要源码

public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {private final ReentrantReadWriteLock.ReadLock readerLock;private final ReentrantReadWriteLock.WriteLock writerLock;final Sync sync;    public ReentrantReadWriteLock() {this(false);}public ReentrantReadWriteLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();readerLock = new ReadLock(this);writerLock = new WriteLock(this);}// 实现了接口 ReadWriteLock 的 writeLock() 方法public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }// 实现了接口 ReadWriteLock 的 readLock() 方法public ReentrantReadWriteLock.ReadLock readLock()  { return readerLock; }// 返回当前线程获取写锁的次数public int getWriteHoldCount() {return sync.getWriteHoldCount();}// 返回当前线程获取读锁的次数public int getReadHoldCount() {return sync.getReadHoldCount();}// 返回当前读锁被获取的次数,但不是占用该锁的线程数,也就是说,一个线程如果 n 次获取该锁,该方法返回 n,而不是 1public int getReadLockCount() {return sync.getReadLockCount();}// 判断写锁是否被获取public boolean isWriteLocked() {return sync.isWriteLocked();}// 静态内部类 ReadLock public static class ReadLock implements Lock, java.io.Serializable {private static final long serialVersionUID = -5992448646407690164L;private final Sync sync;protected ReadLock(ReentrantReadWriteLock lock) {sync = lock.sync;}// 实现了接口 Lock 的方法public void lock() {sync.acquireShared(1);}// 实现了接口 Lock 的方法public void lockInterruptibly() throws InterruptedException {sync.acquireSharedInterruptibly(1);}// 实现了接口 Lock 的方法public boolean tryLock() {return sync.tryReadLock();}// 实现了接口 Lock 的方法public boolean tryLock(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));}// 实现了接口 Lock 的方法public void unlock() {sync.releaseShared(1);}// 实现了接口 Lock 的方法public Condition newCondition() {throw new UnsupportedOperationException();}// 重写了父类 Object 类的方法public String toString() {int r = sync.getReadLockCount();return super.toString() +"[Read locks = " + r + "]";}}// 静态内部类 WriteLock public static class WriteLock implements Lock, java.io.Serializable {private static final long serialVersionUID = -4992448646407690164L;private final Sync sync;protected WriteLock(ReentrantReadWriteLock lock) {sync = lock.sync;}public void lock() {sync.acquire(1);}public void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}public boolean tryLock( ) {return sync.tryWriteLock();}public boolean tryLock(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireNanos(1, unit.toNanos(timeout));}public void unlock() {sync.release(1);}public Condition newCondition() {return sync.newCondition();}// 重写了父类 Object 类的方法public String toString() {Thread o = sync.getOwner();return super.toString() + ((o == null) ?"[Unlocked]" :"[Locked by thread " + o.getName() + "]");}public boolean isHeldByCurrentThread() {return sync.isHeldExclusively();}public int getHoldCount() {return sync.getWriteHoldCount();}}
}

ReentrantReadWriteLock 获取读锁或写锁的方法

// 实现了接口 ReadWriteLock 的 writeLock() 方法
public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock;
}// 实现了接口 ReadWriteLock 的 readLock() 方法
public ReentrantReadWriteLock.ReadLock readLock()  { return readerLock;
}

ReentrantReadWriteLock 获取与释放锁

读锁的获取

// 拿到 ReentrantReadWriteLock 的实例
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 使用 ReentrantReadWriteLock 的实例,调用自己的 readLock() 方法拿到读锁
Lock readLock = readWriteLock.readLock();

读锁的释放

readLock.unlock();

写锁的获取

// 拿到 ReentrantReadWriteLock 的实例
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 使用 ReentrantReadWriteLock 的实例,调用自己的 writeLock() 方法拿到写锁
Lock writeLock = readWriteLock.writeLock();

写锁的释放

readLock.unlock();

ReetrantReadWriteLock 使用场景

适用于读多写少的场景,在此场景中能发挥它的优势。提高了效率的同时,又可以保证线程的安全

并发编程之ReadWriteLock接口相关推荐

  1. JUC并发编程之Callable接口、JUC三大辅助类

    目录 8. Callable接口 8.1 创建线程的多种方式 8.2 概述 8.3 用Callable接口创建Thred线程 8.4 小结(重点) 9. JUC 三大辅助类 9.1 概述 9.2 减少 ...

  2. cyclicbarrier java_Java并发编程之CyclicBarrier和线程池的使用

    原标题:Java并发编程之CyclicBarrier和线程池的使用 下面我们来讲述一下线程池和CyclicBarrier的使用和对比. 一.场景描述 有四个游戏玩爱好者玩游戏,游戏中有三个关卡,每一个 ...

  3. zbb20180929 thread java并发编程之Condition

    java并发编程之Condition 引言 在java中,对于任意一个java对象,它都拥有一组定义在java.lang.Object上监视器方法,包括wait(),wait(long timeout ...

  4. python电路模型编程_14、python开发之路-并发编程之I/O模型

    十四.并发编程之I/O模型 http://www.cnblogs.com/linhaifeng/articles/7454717.html 1.模型介绍 1.1 IO种类 (1)* blocking ...

  5. 并发编程之 Executor 线程池原理与源码解读

    并发编程之 Executor 线程池原理与源码解读 线程是调度 CPU 资源的最小单位,线程模型分为 KLT 模型与 ULT 模型,JVM使用的是 KLT 模型.java线程与 OS 线程保持 1:1 ...

  6. java线程安全的set_Java并发编程之set集合的线程安全类你知道吗

    Java并发编程之-set集合的线程安全类 Java中set集合怎么保证线程安全,这种方式你知道吗? 在Java中set集合是 本篇是<凯哥(凯哥并发编程学习>系列之<并发集合系列& ...

  7. java并发编程之4——Java锁分解锁分段技术

    转载自 java并发编程之4--Java锁分解锁分段技术 并发编程的所有问题,最后都转换成了,"有状态bean"的状态的同步与互斥修改问题.而最后提出的解决"有状态bea ...

  8. java 时间戳_Java并发编程之CAS三CAS的缺点 及解决办法

    Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...

  9. golang并发编程之Ticker

    golang并发编程之Ticker Timer只执行一次,Ticker可以周期的执行 icker是一个定时触发的计时器 它会以一个间隔(interval)往channel发送一个事件(当前时间) 而c ...

  10. 并发编程之CPU缓存架构缓存一致性协议详解(二)

    并发编程之CPU缓存架构&缓存一致性协议详解 CPU高速缓存(Cache Memory) CPU高速缓存 在CPU访问存储设备时,无论是存取数据抑或存取指令,都趋于聚集在一片连续的区域中,这就 ...

最新文章

  1. More than one file was found with OS independent path 'META-INF/rxjava.properties
  2. 《阿丽塔》脑机接口正从科幻走向现实
  3. java 重载 : 1.参数个数不同,2.参数类型不同
  4. 【算法】图文并茂,一文了解 8 种常见的数据结构
  5. [转]黑盒测试和白盒测试
  6. python 100实例_[Python] Python 100例
  7. idea系---懒人
  8. QGraphicsView实现局部缩放,平移,并且能进行选中数据
  9. chrome 历史版本下载
  10. PASCAL中的退出语句
  11. Python初学笔记
  12. 预算少怎么做ASO优化?
  13. 梦游计算机,传承与奉献!《梦幻西游》电脑版《梦游敦煌》完结
  14. Android自定义Lint检查-CustomLint
  15. JS最佳实践——红皮书
  16. python搭建qt开发环境_QT开发环境搭建(Windows)
  17. 德语语法笔记——动词的变位
  18. Java向上转型 向下转型
  19. python模拟登录qq邮箱
  20. 神州数码交换机路由器防火墙ACAP基本配置

热门文章

  1. Linux Centos8上使用系统定时任务crond
  2. 数据集:各地区化妆品销量、人口数量和人均收入
  3. java内省_聊聊Java内省Introspector
  4. 浮动网页html特效代码,网页上可点击关闭的纯代码无图版浮动tips提示特效代码...
  5. 支持向量机(Support Vector Machine SVM)
  6. 公式推导以及代码书写 11-26
  7. 信息管理软件测试工资,【用友软件工资】软件测试工程师待遇-看准网
  8. 2019年 AI 顶会速递
  9. 决策树之随机森林和GBDT
  10. 计算化侦查之根据公交卡记录抓小偷