前一阵有个作反抄袭检测的小伙伴问了我一个问题。javascript
---
在多线程里就是有个变量,我须要读取它来判断是否给它写入一些信息。
打算加锁,可是若是读取时候加入readlock,写入时候加入writelock,
这样作可能读写不一样步。可是若是一块儿加lock效果就跟synchronized同样,效率变差
---复制代码
其实他的问题就是下面的场景:html
我去研究了下读写锁,后来发现其实java官方已经给了答案。使用读写锁加标志位解决读写不一样步的问题。Java ReentrantReadWriteLock
在这先普及下读写锁。java
##代码实例api
直接拿Java官方示例解读了。多线程
class CachedData {
Object data;
volatile boolean cacheValid;
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock(); //1. 上读锁
if (!cacheValid) { //2. 验证cacheValid
// Must release read lock before acquiring write lock
rwl.readLock().unlock(); //3. 解除读锁
rwl.writeLock().lock(); //4. 上写锁
try {
// Recheck state because another thread might have
// acquired write lock and changed state before we did.
if (!cacheValid) { //5. 验证cacheValid
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock(); //6. 上读锁
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read //7. 解除写锁
}
}
try {
use(data);
} finally {
rwl.readLock().unlock();//8. 解除读锁
}
}
}复制代码
好比如今有线程ABCDE五个线程,使用processCachedData()方法,接下来会发现以下步骤。并发
-> DE线程滞后,ABC同时进入到步骤1. 上读锁
-> ABC进入到步骤2. 验证cacheValid。(新实例中cacheValid初始为fasle,因此进入if条件句中)
-> ABC执行步骤3. 解除读锁。
-> 假设此时A率先完成步骤4. 上写锁。
-> BC没法获取写锁,处于等待状态,被阻塞在步骤4。 上写锁。此时D线程执行使用processCachedData()方法,被阻塞在步骤1. 上读锁。
-> A进入到步骤5. 验证cacheValid。
步骤五很关键,若是线程A写完后,解除了写锁,此时新的线程E获取到了写锁,就会写入新数据,此时就不是同步锁了,程序出错。
-> A修改数据,cacheValid置为true。步骤6和步骤7是写锁的降级操做,即写锁释放的时候,先降级为读锁,这样其余等待获取写锁的线程会继续等待,而后再释放写锁,保证同步性。
-> A执行完步骤8,BC阻塞结束,其中一位获取写锁。oracle