目录

Redisson

Redisson - Redis Java client with features of In-Memory Data Grid. Over 50 Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Publish / Subscribe, Bloom filter, Spring Cache, Tomcat, Scheduler, JCache API, Hibernate, MyBatis, RPC, local cache …

Redisson 的优势

提供了看门狗

Redisson提供了一个监控锁的看门狗(watch dog),它的作用是在Redisson实例被关闭前,不断(默认每10s)的延长锁(redis中的目标key)的有效期(默认续期到30s),也就是说,如果一个拿到锁的线程一直没有完成逻辑,那么看门狗会帮助线程不断的延长锁的超时时间,锁不会因为超时而被释放。加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认会在30s内自动过期,不会产生死锁问题; 默认情况下,看门狗的续期时间是30s,也可以通过修改Config.lockWatchdogTimeout来另行指定。 另外Redisson还提供了可以指定leaseTime参数的加锁方法来指定加锁的时间。超过这个时间后锁便自动解开了,不会延长锁的有效期。

提供了多种锁

redisson 还有公平锁、读写锁的实现。

1
compile 'org.redisson:redisson:3.17.6'
1
2
3
4
5
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient() throws Exception {
        Config config = Config.fromYAML(new File("redisson-config.yaml"));
        return Redisson.create(config);
    }

Spring Boot

1
compile 'org.redisson:redisson-spring-boot-starter:3.17.6'
1
2
3
4
5
6
spring:
  application:
    name: springboot-redisson
  redis:
    redisson:
      file: classpath:redisson.yml
1
vim redisson.yml
1
2
3
4
5
6
7
8
singleServerConfig:
  password: 123456
  address: "redis://127.0.0.1:6379"
  database: 1
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.JsonJacksonCodec> {}
transportMode: "NIO"

注意下 codec 配置,默认编码 org.redisson.codec.JsonJacksonCodec。

Available Spring Beans:

  • RedissonClient
  • RedissonRxClient
  • RedissonReactiveClient
  • RedisTemplate
  • ReactiveRedisTemplate

封装 redissonClient 的使用

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/**
 * Redisson分布式锁接口
 * <p>
 * RLock的实现有可重入非公平锁(RedissonLock)、可重入公平锁(RedissonFairLock)、联锁(RedissonMultiLock)、 红锁(RedissonRedLock)、 读锁(RedissonReadLock)、 写锁(RedissonWriteLock)等
 */
public interface DistributedLocker {
    RLock lock(String lockKey);

    RLock lock(String lockKey, long timeout);

    RLock lock(String lockKey, TimeUnit unit, long timeout);

    boolean tryLock(String lockKey, TimeUnit unit, long leaseTime);

    boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime);

    void unlock(String lockKey);

    void unlock(RLock lock);
    /**
     * @param lockKey
     * @param unit
     * @param waitTime
     * @param leaseTime
     * @param supplier 获取锁后要执行的业务逻辑
     * @param scene 业务逻辑的场景,用于打印日志
     * @param <T>
     * @return
     */
    <T> T tryLockAndRun(@Nonnull String lockKey, @Nonnull TimeUnit unit, long waitTime, long leaseTime, @Nonnull Supplier<T> supplier, String scene);
}

/**
 * Redisson分布式锁实现-使用可重入非公平锁(RedissonLock)
 */
@Component
public class RedissonDistributedLocker implements DistributedLocker {
  @Autowired
  private RedissonClient redissonClient;

  @Override
  public RLock lock(String lockKey) {
        RLock lock = this.redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }

  @Override
  public RLock lock(String lockKey, long timeout) {
        RLock lock = this.redissonClient.getLock(lockKey);
        lock.lock(timeout, TimeUnit.SECONDS);
        return lock;
  }

  @Override
  public RLock lock(String lockKey, TimeUnit unit, long timeout) {
        RLock lock = this.redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }

  @Override
  public boolean tryLock(String lockKey, TimeUnit unit, long leaseTime) {
        RLock lock = this.redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(0L, leaseTime, unit);
        } catch (InterruptedException var7) {
            return false;
        }
    }

  @Override
  public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime){
		RLock lock = redissonClient.getLock(lockKey);
		try {
	    	return lock.tryLock(waitTime, leaseTime, unit);
	    } catch (InterruptedException e) {
			return false;
		}
	}

  @Override
	public void unlock(String lockKey){
	    RLock lock = redissonClient.getLock(lockKey);
	    try {
	        if (lock.isLocked()) {
	            lock.unlock();
	        }
	    } catch (IllegalMonitorStateException localIllegalMonitorStateException) {}
	}

  @Override
  public void unlock(RLock lock) {
        try {
            if (lock.isLocked()) {
                lock.unlock();
            }
        } catch (IllegalMonitorStateException var3) {}
    }

  @Override
  public <T> T tryLockAndRun(@Nonnull String lockKey, @Nonnull TimeUnit unit, long waitTime, long leaseTime, @Nonnull Supplier<T> supplier, String scene) {
    final long start = SystemClock.now();
    // 获取分布式锁,最长等待时间:10秒,20秒后自动释放。注意锁与事务的顺序:获取分布式锁 -> 开启事务 -> 执行业务 -> 提交事务 -> 释放分布式锁!!!
    final boolean tryLock = this.tryLock(lockKey, unit, waitTime, leaseTime);
    final long end = SystemClock.now();
    if (!tryLock) {
        log.error("[{}]获取分布式锁失败,lockKey = {},耗时{}ms", scene, lockKey, end - start);
        throw new RequestResultException(JsonCommonCodeEnum.E0004);
    }
        
    // 注意:一定是获取锁成功后,才进行try{}finally{释放锁}
    try {
      log.info("[{}]获取分布式锁成功,lockKey = {},耗时{}ms", scene, lockKey, end - start);
        return supplier.get();
    } finally {
      this.unlock(lockKey);
    }
  }
}

附录