一 引言
多线程的环境下对同一份数据进行读写,会涉及到线程安全的问题。比如一个线程读取数据的时候,另外一个线程在写数据,会导致前后数据的不一致。一个线程在写数据,另一个线程也在写,同样会导致线程前后看到的数据不一致。这时可以在读写方法加入互斥锁,任何时候只能允许一个线程的一个读或写操作,而不允许其他线程的读或写操作,这样是可以解决这样以上的问题,但是效率却大打折扣了。因为在真实的业务场景中,一份数据,读取数据的操作次数通常高于写入数据的操作,而线程与线程间的读读操作是不涉及到线程安全的问题,没有必要加入互斥锁,只要在读-写,写-写期间上锁就行了
读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的。
ReentrantReadWriteLock是可重入的读写锁,允许多个读线程获得ReadLock,但只允许一个写线程获得WriteLock
二 准备
读写锁的机制:
"读-读" 不互斥
"读-写" 互斥
"写-写" 互斥
ReentrantReadWriteLock不支持锁升级(从读锁变成写锁)
ReadWriteLock rtLock = new ReentrantReadWriteLock(); rtLock.readLock().lock(); System.out.println("get readLock."); rtLock.writeLock().lock(); System.out.println("blocking");
这个代码会死锁,没释放读锁就去申请写锁
ReentrantReadWriteLock支持锁降级(从写锁变成读锁)
ReadWriteLock rtLock = new ReentrantReadWriteLock(); rtLock.writeLock().lock(); System.out.println("writeLock"); rtLock.readLock().lock(); System.out.println("get read lock");
以上这段代码虽然不会导致死锁,但没有正确的释放锁。从写锁降级成读锁,并不会自动释放当前线程获取的写锁,仍然需要显示的释放,否则别的线程永远也获取不到写锁。