分布式锁----Redisson

  上一章写了使用Redis来简单的实现的分布式锁,但是实际上官方是不推荐这种方式,官方推荐我们使用一种叫the Redlock algorithm的算法来实现,能保证更好的使用效果,并且这个框架适配了很多种语言,更加的强大,虽然会难一点,而我使用Java开发,当然是使用Redisson
在这里插入图片描述
  Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。
  接下来就开始使用Redisson
  导入jar包,Redisson作为一个队里的框架,在使用时需要导入它的jar包,首先是在普通项目中

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.14.1</version>
</dependency>

  配置Redisson,Redisson的配置有两种方式,一种是通过程序配置,另一种是配置文件

@Configuration
public class RedissonConfig {
    
    
    /**
     * 将Redisson配置到容器中
     */
    @Bean(destroyMethod = "shutdown")//服务停止后销毁
    public RedissonClient redisson() throws IOException {
    
    
        Config config = new Config();
        //集群模式
//        config.useClusterServers().addNodeAddress("127.0.0.1:7004", "127.0.0.1:7001");
        //单节点模式
        config.useSingleServer().setAddress("redis://192.168.0.109:6379").setPassword("没密码可以不配置此项");
        return Redisson.create(config);
    }
}

  接下来就测试关于分布式锁的使用
可重入锁
  如果有A、B两个方法,A去调用B方法,A和B方法都要加锁并且加的是同一把锁,如果是可重入的,当执行A方法去调用B方法,A方法已经加锁了,B检测到A方法已经加锁了就直接用这把锁,执行B的方法,执行完后A释放锁,如果设计为不可重入锁,A和B都需要持有同一把锁,当A占有了锁,B只能等A释放锁才能执行,而A在等B执行完才释放锁,这样就造成了死锁,所以所有的锁都应该设计为可重入锁避免死锁问题

@Autowired
private RedissonClient redissonClient;
public void redsissonDemo() {
    
    
    //获取一把锁,只要锁名字一样就是同一把锁
    RLock lock = redissonClient.getLock("lock");
    // 加锁
    /*
     * 方式一 默认过期时间
     * 加锁方法有两个特点
     * 1. 看门狗机制,在业务逻辑执行期间自动给锁续期
     * 2. 默认锁30S后过期,即使业务宕机没有解锁
     */
    lock.lock();//阻塞式等待
    /*
     * 方式二 指定过期时间
     * 通过源码,此方法传递的超时时间,超时后就删除锁,不会自动续期
     */
    lock.lock(10,TimeUnit.SECONDS);

    try {
    
    
        System.out.println("执行业务略及");
    } finally {
    
    
        // 解锁
        lock.unlock();
    }
}

读写锁
  读写锁分为读锁和写锁,这两个是成对出现,例如当一个服务正在修改一个数据,而其他的服务需要读取这个数据,就必须要等待写锁释放才能读取,如果都是读就互不影响,就是说当写锁存在,读锁就只能等待。加读写锁的好处就在于读取到的数据一定是最新的

@Autowired
private RedissonClient redissonClient;
public void writeLock() {
    
    
    //读写锁
    RReadWriteLock lock = redissonClient.getReadWriteLock("rw-lock");
    //加写锁
    RLock rLock = lock.writeLock();
    rLock.lock();
    try {
    
    
        System.out.println("执行修改数据");
    } finally {
    
    
        rLock.unlock();
    }
}
public void readLock() {
    
    
    //读写锁
    RReadWriteLock lock = redissonClient.getReadWriteLock("rw-lock");
    RLock rLock = lock.readLock();
    rLock.lock();
    try {
    
    
        System.out.println("执行读取数据");
    } finally {
    
    
        rLock.unlock();
    }
}

信号量
  在我们的业务中可能有这样的场景,在某些时刻需要对某些接口进行限流,就可以使用信号量来解决,每个线程执行时,先去获取一个信号量,当信号量全部被获取后,如果还有请求,这些请求都会被阻塞等待,直到获取到信号量,当然也可以提前结束

    public void getSemaphore() throws InterruptedException {
    
    
        RSemaphore sem = redissonClient.getSemaphore("sem");
//        sem.acquire();//获取一个信号量(阻塞式获取)
        boolean b = sem.tryAcquire();//尝试获取信号量
        if (b) {
    
    
            System.out.println("执行业务逻辑");
        }
        //没获取到直接结束
    }

    public void releaseSemaphore() {
    
    
        RSemaphore sem = redissonClient.getSemaphore("sem");
        sem.release();//释放信号量
        System.out.println("执行业务逻辑");
    }

  以上是一些我们常用的锁,当然官方提供的可不仅仅只有这几个,详细文档请参考官方文档(传送门)
  Redisson底层都是使用lua脚本保证了所以它的所有锁都保证了原子性,并且Redisson基于它的看门狗机制,解决了死锁问题并且使用且来也比Redis更加简单强大,推荐在项目中使用Redisson

猜你喜欢

转载自blog.csdn.net/weixin_45481406/article/details/113358432