第6章-ReadWriteLock

6.1 模式简介

  1. 学生们正在一起看老师在黑板上写的板书。这时,老师想擦掉板书,再写新的内容。而学生们说道:“老师,我们还没看完,请先不要擦掉!” 于是,老师就会等待大家都看完。
  2. 当线程 “读取” 实例的状态时,实例的状态不会发生变化。实例的状态仅在线程执行 “写入” 操作时才会发生变化。从实例的状态变化这个观点来看,“读取” 和 “写入” 有着本质的区别。
  3. 在Read-Write Lock模式中,读取操作和写入操作是分开考虑的。在执行读取操作之前,线程必须获取用于读取的锁。而在执行写入操作之前,线程必须获取用于写入的锁。
  4. 由于当线程执行读取操作时,实例的状态不会发生变化,所以多个线程可以同时读取。但在读取时,不可以写入。
  5. 当线程执行写入操作时,实例的状态就会发生变化。因此,当有一个线程正在写人时,其他线程不可以读取或写入。

6.3 Read-Write Lock模式中的角色

6.3.1 Reader(读者)

  1. Reader 角色对 SharedResource 角色执行 read 操作。

6.3.2 Writer(写者)

  1. Writer 角色对 SharedResource 角色执行 write 操作。

6.3.3 SharedResource(共享资源)

  1. SharedResource角色表示的是 Reader 角色和 Writer 角色二者共享的资源。SharedResource角色提供不修改内部状态的操作(read)和修改内部状态的操作(write)。

6.3.4 ReadWriteLock(读写锁)

  1. ReadWriteLock角色提供了SharedResource角色实现read操作和write操作时所需的锁。即实现read操作时所需的 readLock 和 readUnlock,以及实现write操作时所需的 writeLock和writeUnlock。

6.3.5 类图和Timethreads图

第6章-ReadWriteLock

第6章-ReadWriteLock

第6章-ReadWriteLock

6.4 拓展思路的要点

6.4.1 利用“读取”操作的线程之间不会冲突的特性来提高程序性能

  1. Read-Write Lock模式利用了读取操作的线程之间不会冲突的特性。由于读取操作不会修改SharedResource角色的状态,所以彼此之间无需执行互斥处理。因此多个Reader角色可以同时执行read操作,从而提高程序性能。
  2. 但性能的提升也不是这么绝对。Read-Write Lock模式能否提高程序性能,必须通过实际的测量来判定。另外,还需要考虑下面讲述的 “适合读取操作繁重时” 和 “适合读取频率比写入频率高时” 这两个大方针。

6.4.2 适合读取操作繁重时

  1. 在单纯使用Single Threaded Execution模式的情况下,就算是read操作,每次也只能运行一个线程。如果read的操作很繁重(耗费时间),那么使用Read-Write Lock模式比使用Single Threaded Execution 模式更加合适。
  2. 但是,因为Read-Write Lock模式的处理比Single Threaded Execution模式复杂,所以当read的操作很简单(不耗费时间)时,Single Threaded Execution模式反而会更加合适。

6.4.3 适合读取频率比写入频率高时

  1. Read-Write Lock模式的优点是Reader角色之间不会发生冲突。但是,如果写入处理(write)
    的频率很高,Writer角色便会频繁停止Reader角色的处理,这样就无法体现出Read-Write Lock模式的优点了。

6.6 java.util.concurrent.locks 包和 Read-Write Lock模式

6.6.1 java.util.concurrent.locks包

  1. 可用 ReadwriteLock 接口和 ReentrantReadwriteLock 类实现Read-Write Lock模式。
  2. ReentrantReadwriteLock类的主要特征如下:
    • 公平性:当创建ReentrantReadWriteLock类的实例时,我们可以选择锁的获取顺序是否要设为公平(fair)的。如果创建的实例是公平的,那么等待时间久的线程将可以优先获取锁
    • 可重入性:ReentrantReadWriteLock类的锁是可重入的(reentrant)。也就是说,Reader角色的线程可以获取“用于写入的锁”,Writer角色的线程也可以获取“用于读取的锁”。
    • 锁降级:ReentrantReadWriteLock类可以按:获取用于写入的锁->获取用于读取的锁->释放用于写入的锁对锁进行降级。但是,“用于读取的锁” 不可以升级为 “用于写入的锁”。