ReentrantReadWriteLock読み書きロック

最新記事を取得しJavaStormマイクロチャネル公共数に焦点を当てています。
Javaの嵐

アウトライン

ReentrantReadWriteLockロックが別の実装である、我々はすでに、同時にアクセスに一つだけのスレッドを許可する、ReentrantLockのは排他ロックである知っている、とReentrantReadWriteLockは、複数のスレッドが同時に読み取りアクセスを許可しますが、スレッドのスレッドを書いて、読んでいない、書き込みスレッドそして、スレッドの書き込みアクセスを。並行性を改善するための排他ロックに関して。実際には、共有データへのアクセス(例えば、キャッシュ)読み出し動作は、書き込み動作よりもはるかに多くの場合には、その後、ReentrantReadWriteLockは、排他ロックの同時実行性とスループットよりも優れて提供することが可能です。

読み、内部ロックを書くには2つのロック、読み取り用と書き込み操作のための1つを維持します。関連readLockと連携する必要があり、同期メモリ効果書き込みロック動作を保証しなければならないすべての実装をReadWriteLock。言い換えれば、成功は、読み取りロックのスレッドがバージョンがした書き込みロックの前にすべての更新が表示されます取得します。

ReentrantReadWriteLockは、次の機能をサポートしています。

  1. 非ロックモードへの公正かつ公平なアクセスをサポートしています。
  2. サポートリエントラントは、読み取りロックを獲得するためのスレッドを読んだ後も、読み取りロックを得ることができますが、書き込みロックを取得することができ、書き込みスレッドが両方の書き込みロックを取得することも読み込みロックを取得することができ、再び書き込みロックを獲得することができます。
  3. ロックを読み取るために書き込みロックからのダウングレードを許可、その実装は次のようになります。書き込みロックを取得した後、読み取りロックを獲得し、最終的に書き込みロックを解放します。しかし、ロックを書くために、読み取りロックからアップグレードすることはできません。
  4. ロック取得時の両方のサポートの中断をロックし、ロックを読み、書き、
  5. 条件サポート。唯一のロックはConditonの実現を提供して書き込み、ロックがConditonをサポートしていない読んで、readLock()newCondition()はUnsupportedOperationExceptionをスロー..

利用シナリオ

例1:使用リエントラントロックアップグレードキャッシュダウングレードを実行した後

キャッシュでは、有効な同時読み取りをサポートしています。唯一の排他的な書き込みを許可するキャッシュの無効化、。

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class HibernateCache {

    /* 定义一个Map来模拟缓存 */
    private Map<String, Object> cache = new HashMap<String, Object>();

    /* 创建一个读写锁 */
    private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    /**
     * 模拟Hibernate缓存,优先缓存,若缓存不存在写锁更新
     *
     * @param key
     * @return
     */
    public Object getData(String key) {

        /* 上读锁 */
        rwLock.readLock().lock();
        /* 定义从缓存中读取的对象 */
        Object value = null;

        try {
            /* 从缓存中读取数据 */
            value = cache.get(key);

            if (value == null) {
                /* 如果缓存中没有数据,我们就把读锁关闭,直接上写锁【让一个线程去数据库中取数据】 */
                rwLock.readLock().unlock();
                /* 上写锁 */
                rwLock.writeLock().lock();

                try {
                    /* 上了写锁之后再判断一次【我们只让一个线程去数据库中取值即可,当第二个线程过来的时候,发现value不为空了就去缓存中取值】 */
                    if (value == null) {
                        /* 模拟去数据库中取值 */
                        value = "hello";
                        System.out.println("修改换缓存");
                        cache.put(key, value);
                    }
                } finally {
                    /* 写完之后把写锁关闭 */
                    rwLock.writeLock().unlock();
                }
                /* 缓存中已经有了数据,我们再把已经 关闭的读锁打开 */
                rwLock.readLock().lock();
            }
            return value;

        } finally {
            /* 最后把读锁也关闭 */
            rwLock.readLock().unlock();
        }

    }

    public Map<String, Object> getCache() {
        return cache;
    }

    public void setCache(Map<String, Object> cache) {
        this.cache = cache;
    }
}
复制代码

例2:高の同時読み取りと書き込みの共有データ

共有データのみをあなたに西安書き込みデータのマッピングを与えることができた場合、複数のスレッドがデータを読み取ることができます。あなたは、読み取りと書き込みのロックを同時読み取りをサポートし、排他的な書き込み、並行性を向上させるために選択することができます。

コードは以下の通りであります:

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWrite {

    private ReadWrite() {
    }

    private static class singleFactory {
        private static final ReadWrite INSTANCE = new ReadWrite();
    }

    public static ReadWrite getInstance() {
        return singleFactory.INSTANCE;
    }

    /* 共享数据,只能一个线程写数据,可以多个线程读数据 */
    private Object data = null;
    /* 创建一个读写锁 */
    ReadWriteLock rwlock = new ReentrantReadWriteLock();

    /**
     * 读数据,可以多个线程同时读, 所以上读锁即可
     */
    public void get() {
        /* 上读锁 */
        rwlock.readLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + " 准备读数据!");
            /* 休眠 */
            Thread.sleep((long) (Math.random() * 1000));
            System.out.println(Thread.currentThread().getName() + "读出的数据为 :" + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            rwlock.readLock().unlock();
        }

    }

    /**
     * 写数据,多个线程不能同时 写 所以必须上写锁
     *
     * @param data
     */
    public void put(Object data) {

        /* 上写锁 */
        rwlock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + " 准备写数据!");
            /* 休眠 */
            Thread.sleep((long) (Math.random() * 1000));
            this.data = data;
            System.out.println(Thread.currentThread().getName() + " 写入的数据: " + data);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rwlock.writeLock().unlock();
        }
    }
}

复制代码

ユニットテスト

public class LockTest {
    public static void main(String[] args) {
        ReadWrite readWrite = ReadWrite.getInstance();


        for (int i = 0; i < 8; i++) {
            /* 创建并启动8个读线程 */
            new Thread(() -> readWrite.get()).start();

            /*创建8个写线程*/
            new Thread(() -> readWrite.put(new Random().nextInt(8))).start();
        }
    }


}
复制代码

結果:

Thread-0读出的数据为 :null
Thread-1 准备写数据!
Thread-1 写入的数据: 6
Thread-3 准备写数据!
Thread-3 写入的数据: 4
Thread-4 准备读数据!
Thread-2 准备读数据!
Thread-2读出的数据为 :4
Thread-4读出的数据为 :4
Thread-5 准备写数据!
Thread-5 写入的数据: 1
Thread-6 准备读数据!
Thread-6读出的数据为 :1
Thread-7 准备写数据!
Thread-7 写入的数据: 6
Thread-8 准备读数据!
Thread-8读出的数据为 :6
Thread-9 准备写数据!
Thread-9 写入的数据: 4
Thread-10 准备读数据!
Thread-10读出的数据为 :4
Thread-11 准备写数据!
Thread-11 写入的数据: 4
Thread-12 准备读数据!
Thread-12读出的数据为 :4
Thread-13 准备写数据!
Thread-13 写入的数据: 6
Thread-14 准备读数据!
Thread-14读出的数据为 :6
Thread-15 准备写数据!
Disconnected from the target VM, address: '127.0.0.1:55431', transport: 'socket'
Thread-15 写入的数据: 0
复制代码

ルールがここにあります:データが1つの書き込みデータ、つまり、アトミック操作、排他的なスレッドにデータを書き込む準備ができてから行かなければならないの後に書き込みロックを取得します。

そして読み込み可能複数のスレッドを有していてもよく、読み取りロックの場合には、複数のスレッドが同時にデータを読み取ります。


おすすめ

転載: juejin.im/post/5cee32a76fb9a07eb051a401