Redission的读写锁探究
「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
前言
ReentrantLock适合普通场合,如多次加锁,递归调用等,在一些读多写少的场景,我们只需要写的时候互斥就好,没必要全部互斥,所有接下来我们探究下redission的读写锁使用。
读写锁是什么?
在给一段临界区代码加锁,加锁是在进行写操作的时候才会互斥,而在进行读的时候是可以共享的进行访问临界区的
为什么需要读写锁?
有一些公共数据修改的机会比较少,而读的机会却是非常多的,此公共数据的操作基本都是读,如果每次操作都给此段代码加锁,太浪费时间了而且也很浪费资源,降低程序的效率。
因为读操作不会修改数据,只是做一些查询,所以在读的时候不用给此段代码加锁,可以共享的访问,只有涉及到写的时候,互斥的访问就行
读写锁适合于读多写少的场合,可以提高并发效率
读写锁的行为
读写之间是互斥的—–>读的时候写阻塞,写的时候读阻塞,而且读和写在竞争锁的时候,写会优先得到锁
三种关系
- 读和读之间共享关系
- 写和写之间是互斥关系
- 读和写之间是互斥关系
java中的读写锁使用
jdk中提供了读写锁ReentrantReadWriteLock,下面是使用例子
ReentrantReadWriteLock
/**
* @Description: 读写锁
* @Author: jianweil
* @date: 2022/1/27 20:04
*/
public class ReadWriteLockTest {
private static ReentrantReadWriteLock reentrantLock = new ReentrantReadWriteLock();
//读锁
private static ReentrantReadWriteLock.ReadLock readLock = reentrantLock.readLock();
//写锁
private static ReentrantReadWriteLock.WriteLock writeLock = reentrantLock.writeLock();
public static void read() {
readLock.lock();
try {
System.out.println(LocalDateTime.now()+" "+ Thread.currentThread().getName() + "获取读锁,开始执行");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(LocalDateTime.now()+" "+ Thread.currentThread().getName() + "释放读锁");
readLock.unlock();
}
}
public static void write() {
writeLock.lock();
try {
System.out.println(LocalDateTime.now()+" "+ Thread.currentThread().getName() + "获取写锁,开始执行");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(LocalDateTime.now()+" "+ Thread.currentThread().getName() + "释放写锁");
writeLock.unlock();
}
}
public static void main(String[] args) {
new Thread(() -> read(), "Thread1").start();
new Thread(() -> read(), "Thread2").start();
new Thread(() -> write(), "Thread3").start();
new Thread(() -> write(), "Thread4").start();
}
}
测试结果
2022-01-27T20:14:24.427 Thread1获取读锁,开始执行
2022-01-27T20:14:24.427 Thread2获取读锁,开始执行
2022-01-27T20:14:25.427 Thread1释放读锁
2022-01-27T20:14:25.427 Thread2释放读锁
2022-01-27T20:14:25.427 Thread3获取写锁,开始执行
2022-01-27T20:14:26.427 Thread3释放写锁
2022-01-27T20:14:26.427 Thread4获取写锁,开始执行
2022-01-27T20:14:27.428 Thread4释放写锁
可以看出, Thread1和 Thread2是执行的读操作,所以是可以同时访问的,不会阻塞。
而Thread3和Thread4执行的是写锁,Thread3先获得写锁,要等Thread3执行完成释放写锁,Thread4才能获取写锁执行。
redission中读写锁
RReadWriteLock
/**
* @Description: 读写锁
* @Author: jianweil
* @date: 2022/1/27 20:04
*/
public class ReadWriteLockTest2 {
private static final String KEY_LOCKED = "myLock";
private static RedissonClient redissonClient = null;
private static void initRedissonClient() {
// 1. Create config object
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
// 2. Create Redisson instance
ReadWriteLockTest2.redissonClient = Redisson.create(config);
}
public static void read() {
RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(KEY_LOCKED);
readWriteLock.readLock().lock();
try {
System.out.println(LocalDateTime.now()+" "+ Thread.currentThread().getName() + "获取读锁,开始执行");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(LocalDateTime.now()+" "+ Thread.currentThread().getName() + "释放读锁");
readWriteLock.readLock().unlock();
}
}
public static void write() {
RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(KEY_LOCKED);
readWriteLock.writeLock().lock();
try {
System.out.println(LocalDateTime.now()+" "+ Thread.currentThread().getName() + "获取写锁,开始执行");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(LocalDateTime.now()+" "+ Thread.currentThread().getName() + "释放写锁");
readWriteLock.writeLock().unlock();
}
}
public static void main(String[] args) {
initRedissonClient();
new Thread(() -> read(), "Thread1").start();
new Thread(() -> read(), "Thread2").start();
new Thread(() -> write(), "Thread3").start();
new Thread(() -> write(), "Thread4").start();
}
}
测试结果
2022-01-27T20:33:15.295 Thread4获取写锁,开始执行
2022-01-27T20:33:16.296 Thread4释放写锁
2022-01-27T20:33:16.300 Thread2获取读锁,开始执行
2022-01-27T20:33:16.300 Thread1获取读锁,开始执行
2022-01-27T20:33:17.301 Thread2释放读锁
2022-01-27T20:33:17.301 Thread1释放读锁
2022-01-27T20:33:17.305 Thread3获取写锁,开始执行
2022-01-27T20:33:18.306 Thread3释放写锁
Thread4和Thread3是写锁,互斥,所以Thread4执行完成释放写锁,其他线程才能获取读锁或者写锁,因为Thread2和Thread1在Thread4释放写锁获得了读锁,读读是共享的,所以可以交替执行。而Thread3写锁必定在Thread4写锁之后执行。
总结
在redission中封装的读写锁和jdk中的读写锁ReentrantReadWriteLock使用逻辑是一样的。只不过redission中的读写锁是基于redis实现了分布式,功能也更加强大。
写在最后
- 👍🏻:有收获的,点赞鼓励!
- ❤️:收藏文章,方便回看!
- 💬:评论交流,互相进步!
转载自:https://juejin.cn/post/7058272240076341256