读写锁
- 读读并发
- 读写互斥
- 写写互斥
读写锁读锁不支持条件
读锁的条件直接调用ReentrantReadWriteLock的 newCondition 会直接exception
public Condition newCondition() {
throw new UnsupportedOperationException();
}
读写锁使用的例子
package com.shadow.lock;
import com.shadow.aqs.CustomSync;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.*;
@Slf4j(topic = "enjoy")
public class LockTest10 {
static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
static Lock r = rwl.readLock();
static Lock w = rwl.writeLock();
public static void main(String[] args) throws InterruptedException {
//读
new Thread(()->{
log.debug("read 获取 锁");
r.lock();
try {
for (int i = 0; i < 10; i++) {
m1(i);
}
}finally {
r.unlock();
}
},"t1").start();
//写
new Thread(()->{
log.debug("write 获取 锁");
w.lock();
try {
for (int i = 0; i < 20; i++) {
m1(i);
}
}finally {
w.unlock();
}
},"t2");
//读
new Thread(()->{
log.debug("write 获取 锁");
r.lock();
try {
for (int i = 0; i < 20; i++) {
m1(i);
}
}finally {
r.unlock();
}
},"t3").start();
}
public static void m1(int i){
log.debug("exe"+i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
读写支持重入 但是只支持降级不支持升级 (写锁里面再获取读锁),否则会一直阻塞
package com.shadow.lock;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@Slf4j(topic = "enjoy")
public class LockTest11 {
static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
static Lock r = rwl.readLock();
static Lock w = rwl.writeLock();
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
log.debug("read");
w.lock();
try {
log.debug("read 已经获取");
r.lock();
log.debug("write 已经获取");
} finally {
r.unlock();
w.unlock();
}
}, "t1").start();
}
}
//缓存
class CachedData {
Object data;
//判断缓存是否过期
volatile boolean cacheValid;
//定义一把读写锁
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
//处理缓存的方法
void processCachedData() {
rwl.readLock().lock();
//如果缓存没有过期则调用 use(data);
if (!cacheValid) {//要去load真实数据 set给缓存拿到写锁
//释放读锁 因为不支持升级 所以需要先释放
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
//双重检查
if (!cacheValid) {
data = "数据库得到真实数据"
cacheValid = true;
}
//更新缓存之后接着读取 所以先加锁
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read
}
}
try {
//不管上面的if进不进都会执行这里
//缓存可用
use(data);
} finally {
rwl.readLock().unlock();
}
}
}
}
为什么读写锁不能升级只能降级?
假如支持升级
线程t1 请求读锁
线程t2 请求读锁
线程t3 请求写锁
这时候三个线程都拿到锁了
t1执行完然后去请求写锁,因为读写互斥,所以t1 会等待 t2 和t3 执行完才能去拿到写锁
这时候t2 执行完请求写锁,t2 也会去等待t1 和t3 执行完
所以t1 和 t2 就产生了死锁。