目标:一行代码调用,简单粗暴。
基操:自动加锁,自动解锁,自动处理异常,自动处理锁超时等。
安装
redis + redisson
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.39.0</version>
</dependency>
hutool 工具类
xml
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
配置
yml
spring:
data:
redis:
host: xxx
port: 6379
password: xxx
database: x
配置类
java
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* 方便获取 Spring IOC 实例
*
* @author jason
*/
@Configuration
@Import(cn.hutool.extra.spring.SpringUtil.class)
public class BeanConf {
}
工具类
java
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/**
* Redisson 操作工具类
*
* @author jason
*/
@Slf4j
@Component
public class RedissonUtil {
/**
* 锁默认超时时间为(单位:秒)
*/
private static final long LEASE_TIME = 10;
@Autowired
private RedissonClient redissonClient;
public static RedissonUtil instance() {
return SpringUtil.getBean(RedissonUtil.class);
}
/**
* 获取可重入锁
* <p>
* 读写锁(RReadWriteLock)包括读锁和写锁两部分:
* 读锁(Read Lock):允许多个读线程同时访问,但写线程会被阻塞。
* 写锁(Write Lock):独占锁,保证同时只有一个写线程访问,同时也会阻塞其他读线程。
*/
public static RLock getClint(String key) {
return instance().redissonClient.getLock(key);
}
/**
* 加锁
*/
public static void lock(String key) {
getClint(key).lock(LEASE_TIME, TimeUnit.SECONDS);
}
/**
* 解锁
*/
public static void unLock(String key) {
if (getClint(key).isLocked()) {
getClint(key).unlock();
}
}
/**
* 分布式锁,默认超时时间为 LEASE_TIME
*/
public static <T> T lock(String lockKey, Supplier<T> supplier) {
lockKey = "distributed:" + lockKey;
log.info("加锁开始,线程:{}", ThreadUtil.currentThreadGroup().getName());
RedissonUtil.lock(lockKey);
log.info("加锁结束,线程:{}", ThreadUtil.currentThreadGroup().getName());
try {
log.info("执行代码块开始,线程:{}", ThreadUtil.currentThreadGroup().getName());
T t = supplier.get();
log.info("执行代码块结束,线程:{}", ThreadUtil.currentThreadGroup().getName());
return t;
} catch (Exception e) {
log.error(StrUtil.format("执行异常,线程:{}", ThreadUtil.currentThreadGroup().getName()), e);
} finally {
RedissonUtil.unLock(lockKey);
log.info("释放锁结束,线程:{}", ThreadUtil.currentThreadGroup().getName());
}
return null;
}
}
测试
java
@GetMapping("/lock/{key}")
public String lock(@PathVariable String key) {
return RedissonUtil.lock(key, () -> {
ThreadUtil.sleep(30 * 1000);
return "出参";
});
}
cmd
2024-12-26T11:07:41.307 xxx.util.RedissonUtil : 加锁开始,线程:main
2024-12-26T11:07:41.315 xxx.util.RedissonUtil : 加锁结束,线程:main
2024-12-26T11:07:41.315 xxx.util.RedissonUtil : 执行代码块开始,线程:main
2024-12-26T11:08:11.323 xxx.util.RedissonUtil : 执行代码块结束,线程:main
2024-12-26T11:08:11.338 xxx.util.RedissonUtil : 释放锁结束,线程:main
源码
https://gitee.com/zhaomingjian/workspace_jason_demo/tree/master/spring-boot-seckill