『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その８)

<img width="300" alt="javathread.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/165994/9d302410-0471-96c1-f097-d46649d17209.jpeg">

#Read-Write Lockパターン

スレッドがインスタンスの状態を「読む」という処理を行っても、インスタンスの状態は変化しない。変化するのは「書く」という処理を行ったときである。

読むスレッド：
**複数のスレッドが同時に読むのは構わない。しかし、読んでいる間は書くことができない。**

書くスレッド：
**1個のスレッドが書いている間、他のスレッドは読むことも書くこともできない。**

一般的に、排他制御を行うとパフォーマンスは落ちてしまうが、書き込みに対する排他制御と読み取りに対する排他制御を分けて考えると、パフォーマンスを上げることができる。

Dataというクラスのインスタンスに対して、複数のスレッドから読み書きを行うということを考える。
スレッドが、読むためのロックを確保しようとしたとき、
1. 書いているスレッドがすでに存在していたら待たされる。
2. 読んでいるスレッドがすでに存在していても待たされない。
スレッドが、書くためのロックを確保しようとしたとき、
1. 書いているスレッドがすでに存在していたら待たされる。
2. 読んでいるスレッドがすでに存在していたら待たされる。

(コード全体は本書を参照のこと)

```java:ReadWriteLock.java
public final class ReadWriteLock { 
    private int readingReaders = 0;
    private int waitingWriters = 0;
    private int writingWriters = 0;
    private boolean preferWriter = true;
    
    public synchronized void readLock() throws InterruptedException { 
        while (writingWriters > 0 || (preferWriter && waitingWriters > 0)) { 
            wait(); 
        } 
        readingReaders++;
    } 
 
    public synchronized void readUnlock() { 
        readingReaders--;
        preferWriter = true;
        notifyAll(); 
    } 
 
    public synchronized void writeLock() throws InterruptedException { 
        waitingWriters++;
        try { 
            while (readingReaders > 0 || writingWriters > 0) { 
                wait(); 
            } 
        } finally { 
            waitingWriters--;
        } 
        writingWriters++;
    } 
 
    public synchronized void writeUnlock() { 
        writingWriters--;
        preferWriter = false;
        notifyAll(); 
    } 
}
```

waitingWritersフィールドの存在意義
ReaderThreadのスレッドの数がWriterThreadのスレッド数より多い場合、ReadばかりされてWriteがなかなかされなくなる。waitingWriters>0が成り立っているときにはReaderThreadのスレッドをwaitさせることで、WriterThreadが実行開始できない現象を防ぐことができる。

preferWriterフィールドの存在意義
ところが、waitingWritersを考慮するだけでは、今度は、ReaderThreadが実行を開始することができなくなる場合がある。よって、preferWriterフィールで、ReaderThreadとWriterThreadのどちらを優先するかを定めている。サンプルプログラムでは、readが終わった時にtrueにし、writeが終わった時にfalseにしている。

##登場人物

Reader役
Reader役は、SharedResourece役に対してreadを行う。サンプルプログラムでは、ReaderThreadクラスがこれに当たる。

Writer役
Writer役は、SharedResourece役に対してwriteを行う。サンプルプログラムでは、WriterThreadクラスがこれに当たる。

SharedResource役
SharedResource役は、Redaer役とWriter役によって共有されている資源を表す。SharedResource役は、内部状態を変更しない処理(read)と、内部状態を変更する処理(write)を提供する。サンプルプログラムでは、Dataクラスがこれに当たる。

ReadWriteLock役
ReadWriteLock役は、SharedResource役がread処理とwrite処理を実現するためのロックを提供する。サンプルプログラムでは、ReadWriteLockクラスがこれに当たる。


---

関連
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その１)](http://qiita.com/yoshi-yoshi/items/83ecc4476904fa144577)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その２)](http://qiita.com/yoshi-yoshi/items/792ed2e9dc09f63c5004#_reference-5f26b880e1c02b87a1d8)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その３)](http://qiita.com/yoshi-yoshi/items/1d2c0e1279af4adb2e9b)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その４)](http://qiita.com/yoshi-yoshi/items/3b642f91b27120cc4b15)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その５)](http://qiita.com/yoshi-yoshi/items/427be45a8b0044083911)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その６)](http://qiita.com/yoshi-yoshi/items/38187c25619a173ea8b8)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その７)](http://qiita.com/yoshi-yoshi/items/1b6f4e0247496fdaac4c)