概述ReentrantReadWriteLock不知道大家熟悉不?其实在实际项目中很少用到。不管怎样,我从来没有在我的项目中使用过它。ReentrantReadWriteLock称为读写锁,提供读锁,支持多个线程共享同一个锁。它还提供了写锁,这是一种排他锁,与其他读锁或写锁互斥,表示只有一个线程可以持有锁资源。通过两个锁的协同工作,可以最大程度的提升读写的性能,尤其是在读多写少的场景下,大多数场景下读多写少执行。本文主要讲解ReentrantReadWriteLock的使用和应用场景。ReentrantReadWriteLock简介ReentrantReadWriteLock实现了ReadWriteLock接口,可以获取读锁(共享锁)和写锁(独占锁)。同时通过构造方法可以创建锁本身是公平锁还是非公有锁。读写锁机制:读锁、写锁、读锁、共享互斥、写锁、互斥互斥。一个线程进入读锁的前提条件:没有其他线程对写锁的写请求,或者有写请求但是调用线程和持有锁的线程是同一个线程进入读锁的前提条件写锁:没有其他线程的读锁,也没有其他线程的写锁。导致阻塞,那么ReentrantReadWriteLock关于重入呢?关于这个问题,需要引入两个概念,锁升级和锁降级。锁升级:从读锁到写锁。锁降级:由写锁变为读锁;重入时不支持锁升级:持有读锁的同时获取写锁会导致写锁永久等待,需要先释放读,再获取写重入锁降级支持:持有读锁的同时获取读锁一个写锁,导致只有当前线程持有读锁,因为写锁会相互排斥其他锁API介绍构造方法:publicReentrantReadWriteLock():默认构造方法,非公平锁publicReentrantReadWriteLock(booleanfair):true是一个公平锁公共API:publicReentrantReadWriteLock.ReadLockreadLock():返回读锁publicReentrantReadWriteLock.WriteLockwriteLock():返回写锁publicvoidlock():lockpublicvoidunlock():UnlockpublicbooleantryLock():尝试获取锁定代码范式加解锁格式r.lock();try{//临界区}finally{r.unlock();}锁降级w.lock();try{r.lock();//降级为读锁,释放写锁,让其他线程可以读取缓存try{//...}finally{w.unlock();//获取读写锁释放前加锁}}finally{r.unlock();}实战案例验证读写共享模式@TestpublicvoidreadReadMode()throwsInterruptedException{ReentrantReadWriteLockrw=newReentrantReadWriteLock();ReentrantReadWriteLock.ReadLockr=rw.readLock();ReentrantReadWriteLock.WriteLockw=rw.writeLock();线程thread0=newThread(()->{r.lock();尝试{线程。睡眠(1000);系统。出去。println("线程1正在运行"+newDate());}catch(InterruptedExceptione){e.打印堆栈跟踪();}最后{r.开锁();}},"t1");Threadthread1=newThread(()->{r.lock();try{Thread.sleep(1000);System.out.println("Thread2running"+newDate());}catch(InterruptedExceptione){e.printStackTrace();}最后{r.unlock();}},"t2");thread0.start();thread1.start();thread0.join();线程1.join();}运行结果:两个线程同时运行,并且两个线程都获得了读锁验证读写互斥模式ReentrantReadWriteLock.ReadLockr=rw.readLock();重入读WriteLock.WriteLockw=rw.writeLock();Threadthread0=newThread(()->{r.lock();try{Thread.sleep(1000);System.out.println("Thread1running"+newDate());}catch(InterruptedExceptione){e.printStackTrace();}最后{r.unlock();}},"t1");Threadthread1=newThread(()->{w.lock();try{Thread.sleep(1000);System.out.println("Thread2running"+newDate());}catch(InterruptedExceptione){e.printStackTrace();}最后{w.unlock();}},"t2");thread0.start();thread1.start();thread0.join();thread1.join();}运行结果:两个线程间隔1秒,互斥执行realcache例子在什么场景下读多写少?想必第一个想到的就是缓存。ReentrantReadWriteLock是缓存场景中的典型应用。更新缓存时,是先清除缓存还是先更新数据库?先清除缓存:可能会导致刚清除缓存后数据库还没有更新。高并发下,其他线程直接将数据库的过期数据查询到缓存中。这种情况非常严重,直接导致后续所有请求缓存和数据库不一致。先更新数据库:可能会导致一个线程在数据库刚更新完还没有清除缓存之前就从缓存中获取旧数据。这种情况出现的概率比较小,影响范围有限。只有这个查询结果有问题。显然,通常情况下,都是先更新数据库,然后清空缓存。publicclassGenericCachedDao{//缓存对象,这里使用jvm缓存Map
