来源:https://urlify.cn/632yIv
前言
最近面试总是会被问到有没有用过分布式锁、redis锁,由于平时很少接触到,所以只能很无奈的回答“没有”。回来之后就恶补了一下,本文主要做下记录,通过SpringBoot整合redisson来实现分布式锁,并结合demo测试结果。
首先看下大佬总结的图
![](https://i-blog.csdnimg.cn/blog_migrate/c9295580bd3d81e88976ffde4df622d9.png)
正文
增加依赖
-
<!--redis-->
-
<dependency>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-data-redis
</artifactId>
-
</dependency>
-
<!--redisson-->
-
<dependency>
-
<groupId>org.redisson
</groupId>
-
<artifactId>redisson-spring-boot-starter
</artifactId>
-
<version>3.10.6
</version>
-
</dependency>
配置 信息
-
spring:
-
# redis
-
redis:
-
host:
47.103.
5.190
-
port:
6379
-
jedis:
-
pool:
-
# 连接池最大连接数(使用负值表示没有限制)
-
max-active:
100
-
# 连接池中的最小空闲连接
-
max-idle:
10
-
# 连接池最大阻塞等待时间(使用负值表示没有限制)
-
max-
wait: -
1
-
# 连接超时时间(毫秒)
-
timeout:
5000
-
#默认是索引为0的数据库
-
database:
0
配置类
-
/**
-
* redisson 配置,下面是单节点配置:
-
*
-
* @author gourd
-
*/
-
@Configuration
-
public
class RedissonConfig {
-
@Value("${spring.redis.host}")
-
private String host;
-
@Value("${spring.redis.port}")
-
private String port;
-
@Value("${spring.redis.password:}")
-
private String password;
-
-
@Bean
-
public RedissonClient redissonClient() {
-
Config config = new Config();
-
//单节点
-
config.useSingleServer().setAddress(
"redis://" + host +
":" + port);
-
if (StringUtils.isEmpty(password)) {
-
config.useSingleServer().setPassword(
null);
-
}
else {
-
config.useSingleServer().setPassword(password);
-
}
-
//添加主从配置
-
// config.useMasterSlaveServers().setMasterAddress("").setPassword("").addSlaveAddress(new String[]{"",""});
-
// 集群模式配置 setScanInterval()扫描间隔时间,单位是毫秒, //可以用"rediss://"来启用SSL连接
-
// config.useClusterServers().setScanInterval(2000).addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001").addNodeAddress("redis://127.0.0.1:7002");
-
return Redisson.create(config);
-
}
-
}
Redisson工具类
-
/**
-
* redis分布式锁帮助类
-
*
-
* @author gourd
-
*
-
*/
-
public
class RedisLockUtil {
-
-
private
static DistributedLocker distributedLocker = SpringContextHolder.getBean(
"distributedLocker",DistributedLocker.class);
-
-
/**
-
* 加锁
-
* @param lockKey
-
* @return
-
*/
-
public static RLock lock(String lockKey) {
-
return distributedLocker.lock(lockKey);
-
}
-
-
/**
-
* 释放锁
-
* @param lockKey
-
*/
-
public static void unlock(String lockKey) {
-
distributedLocker.unlock(lockKey);
-
}
-
-
/**
-
* 释放锁
-
* @param lock
-
*/
-
public static void unlock(RLock lock) {
-
distributedLocker.unlock(lock);
-
}
-
-
/**
-
* 带超时的锁
-
* @param lockKey
-
* @param timeout 超时时间 单位:秒
-
*/
-
public static RLock lock(String lockKey, int timeout) {
-
return distributedLocker.lock(lockKey, timeout);
-
}
-
-
/**
-
* 带超时的锁
-
* @param lockKey
-
* @param unit 时间单位
-
* @param timeout 超时时间
-
*/
-
public static RLock lock(String lockKey, int timeout,TimeUnit unit ) {
-
return distributedLocker.lock(lockKey, unit, timeout);
-
}
-
-
/**
-
* 尝试获取锁
-
* @param lockKey
-
* @param waitTime 最多等待时间
-
* @param leaseTime 上锁后自动释放锁时间
-
* @return
-
*/
-
public static boolean tryLock(String lockKey, int waitTime, int leaseTime) {
-
return distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, waitTime, leaseTime);
-
}
-
-
/**
-
* 尝试获取锁
-
* @param lockKey
-
* @param unit 时间单位
-
* @param waitTime 最多等待时间
-
* @param leaseTime 上锁后自动释放锁时间
-
* @return
-
*/
-
public static boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
-
return distributedLocker.tryLock(lockKey, unit, waitTime, leaseTime);
-
}
-
-
/**
-
* 获取计数器
-
*
-
* @param name
-
* @return
-
*/
-
public static RCountDownLatch getCountDownLatch(String name){
-
return distributedLocker.getCountDownLatch(name);
-
}
-
-
/**
-
* 获取信号量
-
*
-
* @param name
-
* @return
-
*/
-
public static RSemaphore getSemaphore(String name){
-
return distributedLocker.getSemaphore(name);
-
}
-
}
底层封装
-
/**
-
* @author gourd
-
*/
-
public
interface
DistributedLocker {
-
-
RLock lock(String lockKey);
-
-
RLock lock(String lockKey, int timeout);
-
-
RLock lock(String lockKey, TimeUnit unit, int timeout);
-
-
boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime);
-
-
void unlock(String lockKey);
-
-
void unlock(RLock lock);
-
}
-
-
/**
-
* @author gourd
-
*/
-
@Component
-
public
class
RedisDistributedLocker
implements
DistributedLocker {
-
-
@Autowired
-
private RedissonClient redissonClient;
-
-
@
Override
-
public RLock
lock(
String lockKey) {
-
RLock
lock = redissonClient.getLock(lockKey);
-
lock.
lock();
-
return
lock;
-
}
-
-
@
Override
-
public RLock
lock(
String lockKey, int leaseTime) {
-
RLock
lock = redissonClient.getLock(lockKey);
-
lock.
lock(leaseTime, TimeUnit.SECONDS);
-
return
lock;
-
}
-
-
@
Override
-
public RLock
lock(
String lockKey, TimeUnit unit ,int timeout) {
-
RLock
lock = redissonClient.getLock(lockKey);
-
lock.
lock(timeout, unit);
-
return
lock;
-
}
-
-
@
Override
-
public boolean
tryLock(
String lockKey, TimeUnit unit, int waitTime, int 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);
-
lock.unlock();
-
}
-
-
@
Override
-
public
void
unlock(
RLock lock) {
-
lock.unlock();
-
}
-
}
测试
模拟并发测试
-
/**
-
* redis分布式锁控制器
-
* @author gourd
-
* @since 2019-07-30
-
*/
-
@RestController
-
@Api(tags =
"redisson", description =
"redis分布式锁控制器" )
-
@RequestMapping(
"/redisson" )
-
@Slf4j
-
public
class RedissonLockController {
-
-
/**
-
* 锁测试共享变量
-
*/
-
private Integer lockCount =
10;
-
-
/**
-
* 无锁测试共享变量
-
*/
-
private Integer count =
10;
-
-
/**
-
* 模拟线程数
-
*/
-
private
static
int threadNum =
10;
-
-
/**
-
* 模拟并发测试加锁和不加锁
-
* @return
-
*/
-
@GetMapping(
"/test")
-
@ApiOperation(value =
"模拟并发测试加锁和不加锁")
-
public void lock(){
-
// 计数器
-
final CountDownLatch countDownLatch =
new CountDownLatch(
1);
-
for (
int i =
0; i < threadNum; i ++) {
-
MyRunnable myRunnable =
new MyRunnable(countDownLatch);
-
Thread myThread =
new Thread(myRunnable);
-
myThread.start();
-
}
-
// 释放所有线程
-
countDownLatch.countDown();
-
}
-
-
/**
-
* 加锁测试
-
*/
-
private void testLockCount() {
-
String lockKey =
"lock-test";
-
try {
-
// 加锁,设置超时时间2s
-
RedisLockUtil.lock(lockKey,
2, TimeUnit.SECONDS);
-
lockCount--;
-
log.info(
"lockCount值:"+lockCount);
-
}
catch (Exception e){
-
log.error(e.getMessage(),e);
-
}
finally {
-
// 释放锁
-
RedisLockUtil.unlock(lockKey);
-
}
-
}
-
-
/**
-
* 无锁测试
-
*/
-
private void testCount() {
-
count--;
-
log.info(
"count值:"+count);
-
}
-
-
-
public
class MyRunnable implements Runnable {
-
/**
-
* 计数器
-
*/
-
final CountDownLatch countDownLatch;
-
-
public MyRunnable(CountDownLatch countDownLatch) {
-
this.countDownLatch = countDownLatch;
-
}
-
-
@Override
-
public void run() {
-
try {
-
// 阻塞当前线程,直到计时器的值为0
-
countDownLatch.await();
-
}
catch (InterruptedException e) {
-
log.error(e.getMessage(),e);
-
}
-
// 无锁操作
-
testCount();
-
// 加锁操作
-
testLockCount();
-
}
-
-
}
-
-
}
调用接口后打印值:
![](https://i-blog.csdnimg.cn/blog_migrate/446fe2fc82c6243afe42a32ce1bc4a60.png)
根据打印结果可以明显看到,未加锁的count--后值是乱序的,而加锁后的结果和我们预期的一样。
由于条件问题没办法测试分布式的并发。只能模拟单服务的这种并发,但是原理是一样,希望对大家有帮助。如有错误之处,欢迎指正。
====================================================
代码均已上传至本人的开源项目
spring-cloud-plus:https://blog.csdn.net/HXNLYW/article/details/104635673
-END-
java学长
专注于Java干货分享
扫描上方二维码获取更多Java干货