众所周知,在微服务架构中,往往都会有集群的. 那么并发肯定是少不了的.

单系统我们使用Synchronized Lock Semaphore 去轻而易举的解决掉.

接下来思考一个问题. 为什么不用Spring自带的RedisTemplate或RedisLockRegistry(基于Lock实现的一个分布式锁)呢?

redisTemplate.opsForValue().setIfAbsent();
// 或者
spring-integration-redis的 redisLockRegistry.obtain("key");

补充:
RedisLockRegistry是spring-integration-redis中提供redis分布式锁实现类.主要是通过redis锁+本地锁双重锁的方式实现的一个比较好的锁.

当你在真是项目中使用后你可能会发现这几个问题.

  • 你的业务代码执行时间会超过你的锁时间.
  • 你刚拿到锁后还没设置过期时间,这时候redis宕机了.
  • 反正就是各种恶心你的问题.
  • (补充:RedisLockRegistry底层也是基于lua脚本是实现的,唯一的不足就是没有锁超时的检测延迟机制. 类似redisson的看门狗. 需要自己去实现.)

用了redisson就什么都可以解决了.

Redission通过Netty Future机制,Semaphore (jdk信号量),redis锁实现.
Redisson通过Netty的TimerTask、Timeout 工具完成锁的定期刷新任务.
它也是可重入锁.

代码so easy.

pom


        <!-- https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.12.5</version>
        </dependency>

配置文件

spring.redis.database=1
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=

java

package com.example.yiran.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;

/**
 * @description:
 * @author: wajn
 * @create: 2020-07-12 00:32
 **/
@Configuration
public class RedissonClientConfig {

    @Bean
    public RedissonClient redisson(final RedisProperties redisProperties) throws IOException {
        System.out.println(111);
        Config config = new Config();
        config.useSingleServer()
                .setAddress(String.format("redis://%s:%s", redisProperties.getHost(), redisProperties.getPort()))
                .setDatabase(redisProperties.getDatabase())
        ;
        return Redisson.create(config);
    }


}

    @GetMapping("clear")
    public void clear() throws InterruptedException {
        RLock lock = redissonClient.getLock("locl-test");
        if (lock.tryLock()) {
            System.out.println("11111");
            Thread.sleep(3000000L);
//看门狗会默认查询锁是否过期. 如果快过期了会不断延时过期时间.
            System.out.println("执行完毕业务");
            lock.unlock();
        } else {
            System.out.println("222222");
        }
    }

高阶玩法:

#Redisson配置
singleServerConfig:
  address: "redis://127.0.0.1:6379"
  password: null
  clientName: null
  database: 1 #选择使用哪个数据库0~15
  idleConnectionTimeout: 10000
  pingTimeout: 1000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500
  reconnectionTimeout: 3000
  failedAttempts: 3
  subscriptionsPerConnection: 5
  subscriptionConnectionMinimumIdleSize: 1
  subscriptionConnectionPoolSize: 50
  connectionMinimumIdleSize: 32
  connectionPoolSize: 64
  dnsMonitoringInterval: 5000
  #dnsMonitoring: false

threads: 0
nettyThreads: 0
codec:
  class: "org.redisson.codec.JsonJacksonCodec"
transportMode: "NIO"

package com.example.yiran.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;

/**
 * @description:
 * @author: wajn
 * @create: 2020-07-12 00:32
 **/
@Configuration
public class RedissonClientConfig {

    @Bean
    public RedissonClient redisson() throws IOException {
        System.out.println(111);
        // 本例子使用的是yaml格式的配置文件,读取使用Config.fromYAML,如果是Json文件,则使用Config.fromJSON
        Config config = Config.fromYAML(this.getClass().getClassLoader().getResource("redisson-config.yml"));
        return Redisson.create(config);
    }

}