分布式锁实现
configRedis
packagecom.dhl.utils.config;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.data.redis.connection.RedisConnectionFactory;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.data.redis.core.StringRedisTemplate;
importorg.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
importorg.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author YHS
*/
@Configuration
publicclassRedisConfig {
@Bean
publicRedisTemplate<String, Object>redisTemplate(RedisConnectionFactoryfactory) {
RedisTemplate<String, Object>template=newRedisTemplate<>();
template.setConnectionFactory(factory);
// key采用String的序列化方式
template.setKeySerializer(newStringRedisSerializer());
// value序列化方式采用jackson
template.setValueSerializer(newGenericJackson2JsonRedisSerializer());
template.afterPropertiesSet();
returntemplate;
}
@Bean
publicStringRedisTemplatestringRedisTemplate(RedisConnectionFactoryfactory) {
StringRedisTemplatetemplate=newStringRedisTemplate();
template.setConnectionFactory(factory);
// key采用String的序列化方式
template.setKeySerializer(newStringRedisSerializer());
// value序列化方式采用jackson
template.setValueSerializer(newGenericJackson2JsonRedisSerializer());
returntemplate;
}
}
redisLockUtils
packagecom.dhl.utils;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.data.redis.core.BoundValueOperations;
importorg.springframework.data.redis.core.StringRedisTemplate;
importorg.springframework.data.redis.core.script.DefaultRedisScript;
importorg.springframework.stereotype.Component;
importorg.springframework.util.StringUtils;
importjava.util.*;
importjava.util.concurrent.TimeUnit;
/**
* 实现redis加减原子操作
*
* @author YHS
*/
@Component
publicclassRedisLockUtils {
/**
* 锁标志
*/
privateStringlockKey="lock";
@Autowired
privateStringRedisTemplatestringRedisTemplate;
/**
* 尝试获取锁
* @param requestId
* @param expireTime
* @return 是否成功?
*/
publicBooleangetLock(StringrequestId, intexpireTime) {
// 绑定一个key对象
BoundValueOperations<String, String>operations=stringRedisTemplate.boundValueOps(lockKey);
Stringvalue=operations.get();
while (true) {
// 加锁
if (operations.setIfAbsent(requestId, expireTime, TimeUnit.SECONDS)) {
returntrue;
}
if (StringUtils.hasLength(value) &&requestId.equals(value)){
returntrue;
}
}
}
/**
* 释放锁
* @param requestId
* @return 释放成功?
*/
publicbooleanreleaseLock(StringrequestId) {
Stringscript=" if redis.call ('get',KEYS[1]) == ARGV[1] then "+" return redis.call('del', KEYS[1]) "+" else return 0 end ";
DefaultRedisScript<Long>redisScript=newDefaultRedisScript<>(script, Long.class);
Longexecute=stringRedisTemplate.execute(redisScript, Collections.singletonList(lockKey), requestId);
LonglockFlag=1L;
returnlockFlag.equals(execute);
}
/**
* 锁续期
* @param time 续期时间
* @param requestId uuid---唯一标识
* @return 线程对象
*/
publicThreadcreateLifeThread(inttime, StringrequestId) {
returnnewThread(() -> {
while (true) {
try {
TimeUnit.SECONDS.sleep(time*2/3);
Stringscript=" if redis.call('get', KEYS[1]) == ARGV[1] then "+" return redis.call('expire', KEYS[1], ARGV[2]) "+" else return '0' end ";
// 设置参数
ArrayListargs=newArrayList<>(2);
args.add(requestId);
args.add(time);
DefaultRedisScript<Long>redisScript=newDefaultRedisScript<>(script, Long.class);
StringRedisTemplateredisTemplate=stringRedisTemplate;
redisTemplate.execute(redisScript, Arrays.asList(lockKey), args);
} catch (InterruptedExceptione) {
return;
}
}
});
}
}
mapper
@Select("select sum from redis_lock limit 1")
intselect();
@Update("update redis_lock set sum=#{sum}")
intupdate(@Param("sum") intsum);
service
@Resource
privateRedisLockMapperredisLockMapper;
@Override
publicvoidaddSum() {
intsum=redisLockMapper.select();
redisLockMapper.update(++sum);
}
controller测试
@GetMapping("/redisLockSum")
publicStringredisLockSum() {
StringrequestId=UUID.randomUUID().toString();
intexpire=5;
// 1.获取锁
System.out.println("是否成功获取锁"+redisLockUtils.getLock(requestId, expire));
// 启动子线程守护
ThreadlifeThread=redisLockUtils.createLifeThread(expire, requestId);
try {
// 线程守护
lifeThread.setDaemon(true);
// 启动生命线程
lifeThread.start();
System.out.println("是否成功获取锁"+redisLockUtils.getLock(requestId, expire));
redisLockService.addSum();
System.out.println("是否成功获取锁"+redisLockUtils.getLock(requestId, expire));
redisLockService.addSum();
System.out.println("是否成功获取锁"+redisLockUtils.getLock(requestId, expire));
redisLockService.addSum();
return"添加成功";
} catch (Exceptione) {
e.printStackTrace();
} finally {
// 关闭线程守护
lifeThread.interrupt();
System.out.println(redisLockUtils.releaseLock(requestId));
}
return"添加失败";
}
@GetMapping("/sum")
publicStringsum() {
redisLockService.addSum();
return"添加成功";
}
测试数据
数据100次
线程4个
![](https://i-blog.csdnimg.cn/blog_migrate/1398fd7ff54953bafc645f077dae2644.png)
测试结果
测试前
![](https://i-blog.csdnimg.cn/blog_migrate/570fd54fac5f2c9b9aca7fcaf904df72.png)
测试后
不加锁
![](https://i-blog.csdnimg.cn/blog_migrate/4f2222d388bb3b5b31930cc32b564aae.png)
加锁
![](https://i-blog.csdnimg.cn/blog_migrate/1d574819eb86fc795b501e247400d29b.png)