zoukankan      html  css  js  c++  java
  • Redisson分布式锁

    Redisson分布式

    GitHub中文文档

    概念:是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务

    引入依赖

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

    配置

    @Configuration
    public class MyRedissonConfig {
    
        @Bean(destroyMethod = "shutdown")
        public RedissonClient redissonClient() throws IOException{
            //1.配置连接
            Config config = new Config();
            config.useSingleServer()
                    .setPassword("123456")
                    //可以用"rediss://"来启用SSL连接
                    .setAddress("redis://123.56.16.54:6379");
            //2.创建客户端
            RedissonClient redissonClient= Redisson.create(config);
            return redissonClient;
        }
    }
    
    

    分布式锁

    1、可重入锁

    @ResponseBody
        @GetMapping("/hello")
        public String hello() {
    
            //1、获取一把锁,只要锁的名字一样,就是同一把锁
            RLock lock = redisson.getLock(" my-lock ");
            //2、加锁
            lock.lock();//阻塞式等待。默认加的锁都是30s时间。
            //1)、锁的自动续期,如果业务超长,运行期间自动给锁续上新的30s。不用担心业务时间长,锁自动过期被用特
            //2)、加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认在30s以后自动删除。
            try{
                System.out.println("加锁成功,执行业务..." + Thread.currentThread().getId());
                Thread.sleep(30000);
            } catch (Exception e) {
    
            } finally {
    //3、解锁将设解锁代码没有运行,redisson会不会出现死锁
                System.out.println("释放锁..." + Thread.currentThread().getId());
                lock.unlock();
            }
            return "hello";
        }
    

    基于Redis的Redisson分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口

    大家都知道,如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。

    try {
                while (true) {
                    ttl = tryAcquire(leaseTime, unit, threadId);
                    // lock acquired
                    if (ttl == null) {
                        break;
                    }
    
                    // waiting for message
                    if (ttl >= 0) {
                        try {
                            future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                        } catch (InterruptedException e) {
                            if (interruptibly) {
                                throw e;
                            }
                            future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                        }
                    } else {
                        if (interruptibly) {
                            future.getNow().getLatch().acquire();
                        } else {
                            future.getNow().getLatch().acquireUninterruptibly();
                        }
                    }
                }
            } finally {
                unsubscribe(future, threadId);
            }
    

    另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。

    // 加锁以后10秒钟自动解锁,不会续期
    // 无需调用unlock方法手动解锁
    lock.lock(10, TimeUnit.SECONDS);//10秒自动解锁,自动解锁时间一定要大于业务的执行时间。
    //问题:Lock.Lock(10,TimeUnit.SECONDS);在锁时间到了以后,不会自动续期。
    //1、如果我们传递了锁的超时时间,就发送给redis执行脚本,进行占锁,默认超时就是我们指定的时间
    //2、如果我们未指定锁的超时时间,就使用30*1000(LockivatchdogTimeout看门狗的默认时间)
    //只要占锁成功,就会启动一个定时任务(重新给看门狗定义过期时间,新的过期时间是默认的30s),每个10s自动续期到30s
    // internalLockLeaseTime【看门狗时间】/3,10s后
    
    // 尝试加锁,最多等待100秒,超出不等,上锁以后10秒自动解锁
    boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
    if (res) {
       try {
         ...
       } finally {
           lock.unlock();
       }
    }
    

    2、公平锁

    保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程。所有请求线程会在一个队列中排队,当某个线程出现宕机时,Redisson会等待5秒后继续下一个线程,也就是说如果前面有5个线程都处于等待状态,那么后面的线程会等待至少25秒。

    RLock fairLock = redisson.getFairLock("anyLock");
    // 最常见的使用方法
    fairLock.lock();
    
    // 10秒钟以后自动解锁
    // 无需调用unlock方法手动解锁
    fairLock.lock(10, TimeUnit.SECONDS);
    
    // 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
    boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);
    ...
    fairLock.unlock();
    

    3、读写锁

    分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。

    RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
    // 最常见的加锁使用方法
    rwlock.readLock().lock();
    // 或
    rwlock.writeLock().lock();
    
    
    // 10秒钟以后自动解锁
    // 无需调用unlock方法手动解锁
    rwlock.readLock().lock(10, TimeUnit.SECONDS);
    // 或
    rwlock.writeLock().lock(10, TimeUnit.SECONDS);
    
    // 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
    boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
    // 或
    boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
    ...
    lock.unlock();
    

    进行写操作之前不能有锁,进行读操作之前可以有读锁,不能有写锁

    4、信号量

    	@ResponseBody
        @GetMapping("/acquire")
        public String AcquireSemaphore(){
            RSemaphore semaphore = redisson.getSemaphore("semaphore");
            //需要获取几个信号量参数就写几,默认为1
            boolean b = semaphore.tryAcquire();
            if(b){
                //获取成功
                return "获取成功:信号量-1..."+"当前信号量"+semaphore.availablePermits();
            }else{
                return "获取失败:等待...."+"当前信号量"+semaphore.availablePermits();
            }
        }
    
        @ResponseBody
        @GetMapping("/release")
        public String releaseSemaphore(){
            RSemaphore semaphore = redisson.getSemaphore("semaphore");
            semaphore.release();//semaphore.release(4);表示一次性释放4个信号量
            return "释放成功:信号量+1......"+"当前信号量"+semaphore.availablePermits();
        }
    

    5、闭锁

    (CountDownLatch)

    RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
    latch.trySetCount(3);//redis中存在一个anyCountDownLatch=3,当其等于0时就闭锁
    latch.await();
    
    
    // 在其他线程或其他JVM里
    RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
    latch.countDown();//redis中的anyCountDownLatch减一
    
  • 相关阅读:
    Fedora install chrome
    Ubuntu13.04 安装 chrome
    cjb
    屏蔽视频广告
    tars环境部署
    rpm包安装失败的解决办法
    Java环境变量配置错误
    Protobuf的安装使用
    fpm打包工具
    gcc6.3的安装
  • 原文地址:https://www.cnblogs.com/jklixin/p/13212864.html
Copyright © 2011-2022 走看看