1.配置类
@Primary
@Bean("clusterObjectRedisTemplate")
public RedisTemplate<String, Object> objectTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// key采用String的序列化方式
template.setKeySerializer(new StringRedisSerializer());
// value序列化方式采用jackson
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.afterPropertiesSet();
return template;
}
2.获取锁
2.1 lua脚本
private static final String TRY_LOCK_SCRIPT =
"if redis.call('SET',KEYS[1], ARGV[1], 'NX', 'EX', ARGV[2]) " +
"then " +
" return 1 " +
"else" +
" return 0 " +
"end";
2.2 获取锁
/**
* 获取锁,获取锁成功返回true,获取失败返回false
* @param lockKey 锁key值
* @param identify 锁value值,通过value对比释放锁
* @param expireMillisecond 过期时间
* @return
*/
public Boolean lock(String lockKey, String identify, Long expireMillisecond) {
try {``
RedisScript<Long> redisScript = new DefaultRedisScript<>(TRY_LOCK_SCRIPT, Long.class);
Object result = objectTemplate.execute(redisScript, Collections.singletonList(lockKey), identify, expireMillisecond);
if (LOCK_SUCCESS.equals(result)) {
return Boolean.TRUE;
}
} catch (Exception e) {
logger.error("获取锁失败,lockKey=[{}], identify=[{}]", lockKey, identify, e);
}
return Boolean.FALSE;
}
2.3 尝试多次获取锁
/**
* 尝试获取锁
* @param key
* @param value
* @param expireMillisecond 过期时间
* @param waitMillisecond 等待锁的时间
*/
public Boolean tryLock(String key,String value, Long expireMillisecond, Long waitMillisecond) {
while(waitMillisecond > 0 ){
Boolean lockFlag = lock(key, value, expireMillisecond);
if(lockFlag) {
return true;
}else{
try {
Thread.sleep(INTERVAL_MILLISECOND);
} catch (InterruptedException e) {
logger.error("睡眠中断",e);
}
waitMillisecond = waitMillisecond - INTERVAL_MILLISECOND;
}
}
return false;
}
3.释放锁
3.1 lua脚本
private static final String RELEASE_LOCK_SCRIPT =
"if redis.call('get', KEYS[1]) == ARGV[1] " +
"then " +
" return redis.call('del', KEYS[1]) " +
"else " +
" return 0 " +
"end";
3.2 释放锁
/**
* 释放锁,释放成功返回true,释放失败返回false
* @param lockKey 锁key值
* @param identify 判断锁value是否相同,相同才释放锁
* @return
*/
public Boolean unLock(String lockKey, String identify) {
try {
RedisScript<Long> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_SCRIPT, Long.class);
Object result = objectTemplate.execute(redisScript, Collections.singletonList(lockKey), identify);
if (LOCK_SUCCESS.equals(result)) {
return Boolean.TRUE;
}
} catch (Exception e) {
logger.error("解锁失败,lockKey=[{}], identify=[{}]", lockKey, identify, e);
}
return Boolean.FALSE;
}
4.获取锁测试
@Test
public void testLock() throws InterruptedException {
int threadCount = 4;
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
int j = 1;
for (int i = 0; i < threadCount; i++) {
executorService.submit(() -> {
String uuid = UUIDUtil.getUUID();
Boolean lock = redisUtil.tryLock("a12312312312dadq", uuid, 8 * 1000L,6* 1000L);
if (lock) {
try {
log.error("线程[{}]正在执行中,uuid:{}", Thread.currentThread().getName(), uuid);
try {
Thread.sleep(7000);
log.error("线程[{}]执行完毕", Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
boolean releaseResult = redisUtil.unLock("a12312312312dadq", uuid);
log.error("线程[{}]释放redis,uuid:{},释放状态:{}", Thread.currentThread().getName(), uuid, releaseResult);
}
} else {
log.error("线程[{}]获取锁失败", Thread.currentThread().getName());
}
countDownLatch.countDown();
}, j++);
}
countDownLatch.await();
}