实现分布式锁的大致流程如下:
- 1、通过set命令设置锁
- 2、判断返回结果是否是OK
- 1)Nil,获取失败,结束或重试(自旋锁)
- 2)OK,获取锁成功
- 执行业务
- 释放锁,DEL 删除key即可
- 3、异常情况,服务宕机。超时时间EX结束,会自动释放锁
1.代码实现
定义一个锁接口:
package com.xxx.task.utils;
/**
* @author 董志伟
*/
public interface RedisLock {
boolean lock(long releaseTime);
void unlock();
}
先定义一个锁工具:
package com.xxx.task.utils;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.concurrent.TimeUnit;
/**
* @author 董志伟
*/
public class SimpleRedisLock implements RedisLock{
private StringRedisTemplate redisTemplate;
/**
* 设定好锁对应的 key
*/
private String key;
/**
* 锁对应的值,无意义,写为1
*/
private static final String value = "1";
public SimpleRedisLock(StringRedisTemplate redisTemplate, String key) {
this.redisTemplate = redisTemplate;
this.key = key;
}
public boolean lock(long releaseTime) {
// 尝试获取锁
Boolean boo = redisTemplate.opsForValue().setIfAbsent(key, value, releaseTime, TimeUnit.SECONDS);
// 判断结果
return boo != null && boo;
}
public void unlock(){
// 删除key即可释放锁
redisTemplate.delete(key);
}
}
在定时任务中使用锁:
package com.xxx.task.job;
import com.xxx.task.utils.SimpleRedisLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @author 董志伟
*/
@Slf4j
@Component
public class HelloJob {
@Autowired
private StringRedisTemplate redisTemplate;
@Scheduled(cron = "0/10 * * * * ?")
public void hello() {
// 创建锁对象
RedisLock lock = new SimpleRedisLock(redisTemplate, "lock");
// 获取锁,设置自动失效时间为50s
boolean isLock = lock.lock(50);
// 判断是否获取锁
if (!isLock) {
// 获取失败
log.info("获取锁失败,停止定时任务");
return;
}
try {
// 执行业务
log.info("获取锁成功,执行定时任务。");
// 模拟任务耗时
Thread.sleep(500);
} catch (InterruptedException e) {
log.error("任务执行异常", e);
} finally {
// 释放锁
lock.unlock();
}
}
}
这只是简单的锁,如果实现具体的分布式锁 请参考另一篇博客 Redission 实现分布式锁