ReentrantReadWriteLock的使用
ReentrantReadWriteLock的规则是:
多线程情况下:读-写互斥、写-读互斥、写-写互斥、读-读共享
验证“读-写互斥、写-读互斥、写-写互斥、读-读共享”
//单个线程 读-读 不互斥 r.lock(); r.lock(); System.out.println("读-读 不互斥"); r.unlock(); r.unlock(); //多个线程 读-读 不互斥 new Thread(() -> { r.lock(); try {Thread.sleep(2000L);} catch (InterruptedException e) {} r.unlock(); }).start(); new Thread(() -> { r.lock(); System.out.println("立刻执行"); r.unlock(); }).start(); //单个线程 读-写 互斥,不存在锁升级 r.lock(); w.lock(); System.out.println("ok"); w.unlock(); r.unlock(); //多个线程 写-读 互斥 new Thread(() -> { w.lock(); try {Thread.sleep(10000000L);} catch (InterruptedException e) {} w.unlock(); }).start(); try {Thread.sleep(500L);} catch (InterruptedException e) {}//等第一个线程 new Thread(() -> { r.lock(); System.out.println("我能获得读锁"); r.unlock(); }).start();
ReentrantReadWriteLock使用场景
对于数据比较敏感的场景,
读锁:在读取数据时是不能出现多次读取不一致的情况的,这点有点像可重复读和幻读,
写锁:写数据时,又不能同时读取数据
private final Map<String, Data> m = new TreeMap<String, Data>(); private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock r = rwl.readLock(); private final Lock w = rwl.writeLock(); public Data get(String key) { r.lock(); try { return m.get(key); } finally { r.unlock(); } } public String[] allKeys() { r.lock(); try { return m.keySet().toArray(); } finally { r.unlock(); } } public Data put(String key, Data value) { w.lock(); try { return m.put(key, value); } finally { w.unlock(); } } public void clear() { w.lock(); try { m.clear(); } finally { w.unlock(); } }
锁降级
单线程情况下有个特殊的点:读-写不互斥、即降级
//单个线程 写-读 不互斥,降级 w.lock(); r.lock(); System.out.println("ok"); r.unlock(); w.unlock(); //降级后,其他线程读不能进来 因为写锁并没有完全释放,如果按照下面这种方式做,那么降级将变的没有任何意义,因为你完全可以用一把写锁就代替了 new Thread(() -> { w.lock(); r.lock(); System.out.println("我已经降级了"); try {Thread.sleep(2000L);} catch (InterruptedException e) {} r.unlock(); w.unlock(); }).start(); new Thread(() -> { r.lock(); System.out.println("我能进去"); r.unlock(); }).start(); //正确的姿势如下,这样就能保证在写锁没释放前转化为读锁,写锁紧接着释放,其他线程的读就可以进去了 new Thread(() -> { w.lock(); r.lock(); w.unlock(); System.out.println("我已经降级了"); try {Thread.sleep(2000L);} catch (InterruptedException e) {} r.unlock(); }).start(); new Thread(() -> { r.lock(); System.out.println("我能进去"); r.unlock(); }).start();
锁降级可以帮助我们拿到当前线程修改后的结果而不被其他线程所破坏
锁降级的典型用法
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock r = rwl.readLock(); private final Lock w = rwl.writeLock(); w.lock(); //writing r.lock(); w.unlock(); //reading r.unlock();