java相对主流分布式锁 - redis的Redisson (Java implementation)

the Redlock 设计

1.引入依赖
<!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
        <!-- 以后试用redisson作为分布式锁,分布式对象等功能框架-->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.12.0</version>
        </dependency>
2.配置redis

整理单节点模式的Configuration

@Configuration
public class MyRedissonConfig {

    /**
     * 所有的对redisson的试用 都通过RedissonClient对象
     * @return
     * @throws IOException
     */
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson() throws IOException{
       Config config = new Config();
       //集群模式
//       config.useClusterServers().addNodeAddress("localhost:3001","127.0.0.1:6379");
        //单节点模式
        //1.创建配置
        config.useSingleServer().setAddress("redis://192.168.31.125:6379");
        //2.创建实例RedissonClient
       return Redisson.create(config);
   }

}

测试类 测试配置完成:

这个测试有一些必要性 能检验出你的maven引入依赖是否完整合乎版本的导入项目 能再逻辑之前,提前发现外部问题

比如 本人idea装载maven包 必须重启才能获取到正确的包 能有效检验

@Autowired
    RedissonClient redissonClient;

    @Test
    public void redisson(){
        System.out.println(redissonClient);
    }

控制台如下:

org.redisson.Redisson@1b69fc07

延伸:文档中配置有两种方式

程序化配置或者配置文件配置

a.程序化配置

Redisson程序化的配置方法是通过构建Config对象实例来实现的。例如:

Config config = new Config();
config.setTransportMode(TransportMode.EPOLL);
config.useClusterServers()
      //可以用"rediss://"来启用SSL连接
      .addNodeAddress("redis://127.0.0.1:7181");

b.文件方式配置

Redisson既可以通过用户提供的YAML格式的文本文件来配置

通过yaml格式配置

Redisson的配置文件可以是或YAML格式。 也通过调用config.fromYAML方法并指定一个File实例来实现读取YAML格式的配置:

Config config = Config.fromYAML(new File("config-file.yaml"));
RedissonClient redisson = Redisson.create(config);

调用config.toYAML方法可以将一个Config配置实例序列化为一个含有YAML数据类型的字符串:

Config config = new Config();
// ... 省略许多其他的设置
String jsonFormat = config.toYAML();
3.分布式锁

a.可重入锁

基于Redis的Redisson分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口。同时还提供了异步(Async)反射式(Reactive)RxJava2标准的接口。

RLock lock = redisson.getLock("anyLock");
// 最常见的使用方法
lock.lock();

实际使用DEMO:

* redis的看门狗机制 解决了两个问题: * 1.锁的自动续期 如果业务超长,运行期间会自动给锁续期 不用担心业务时间长锁过期被删掉。 * 2.加锁业务完成,不会给当前锁续期,即使不手动解锁 lock.unlock() 锁也会过去 无死锁问题。

@ResponseBody
    @GetMapping("/redisson")
    public String redisson(){
        //1.调用getLock获取一把锁 只要锁名字一样 就是同一把锁
        RLock myLock = redisson.getLock("myLock");

        //2 加锁 阻塞式等待
        /**
         * redis的看门狗机制 解决了两个问题:
         *  1.锁的自动续期  如果业务超长,运行期间会自动给锁续期 不用担心业务时间长锁过期被删掉。
         *  2.加锁业务完成,不会给当前锁续期,即使不手动解锁 lock.unlock() 锁也会过去 无死锁问题。
         */
        myLock.lock();
         myLock.lock(10,Time);
      try{
          System.out.println("加锁成功后 执行业务");
          System.out.println("当前线程ID:" + Thread.currentThread().getId());
          Thread.sleep(10000);
      }catch (Exception e ){

      }finally {
          //不论业务执行结果如何 解锁
          System.out.println("释放锁");
          System.out.println("当前线程ID:" + Thread.currentThread().getId());
          //redis的看门狗
          myLock.unlock();
      }
      return "reddison";
    }

延伸
了解看门狗机制:

myLock.lock();
1.如果传递了锁的超时时间,就发送给redis 执行脚本,进行占锁,默认超时时间是传递的时间
2.如果未指定超时时间,就使用30*1000【LockWatchdogTimeOut 看门狗的默认时间 默认30s】
只要占锁成功,就会启动一个定时任务【重新给所设置过期时间,新的过期时间就是看门狗的默认时间】
internalLockLeaseTime 续期时间 默认:看门狗时间/3 即:默认10s
每隔10s都自动续时,需要到满看门狗时间 30s (即:过期时间剩余20s 看门狗定时任务进程就让过期实际时间变成30s)

推荐方法:
myLock.lock(30, TimeUnit.SECONDS);
即:不触发看门狗,给与对应的过期时间 30s 满足大多数操作时常。
节省了整个续期定时任务操作。手动解锁(即使没有解锁,30s也会解开)。


延伸
trylock 解决lock的阻塞方案 限时阻塞:

trylock 控制阻塞时间:
 myLock.lock(10, TimeUnit.SECONDS);
 myLock.trylock(100,10,TimeUnit.SECONDS);
 trylock区别lock:
 lock为阻塞方法
 trylock尝试最多等待100s,上锁后10自动解锁
 boolean res = myLock.trylock(100,10,TimeUnit.SECONDS);
 if(res){
 try{
 …
 } finally{
 mylock.unlock();
 }
 }

延伸
公平锁:
默认占锁都是抢占,让请求有序占锁

请求的有序占用锁 (默认的是一个锁释放,其他抢占)
 Rlock fairLock = redisson.getFairLock(“anyLock”);
 fairLock.lock();