实现的诉求,多台服务器上,执行相同的方法,一次只能执行一个,如果多个请求了执行方法,那么排队等待执行。
方案:采用三方服务redis的key做唯一标识控制。超时后。
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import com.ccjr.commons.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
/**
* @desc REDIS分布式锁工具类
* @author 陈惟鲜 chenweixian
* @date 2020年8月19日 下午4:20:46
*
*/
@Slf4j
public class RedisLockUtil {
@SuppressWarnings("unchecked")
private static RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) SpringUtils.getBean("redisTemplate");
private static long lockTimeout = 5*1000L; //锁定时间30s
/**
* 加锁
*
* @param key
* @param value 当前时间+ 超时时间
* @return
*/
public static boolean lock(String key, long currvalue) {
String value = currvalue+lockTimeout+"";
//未加锁,则加锁
if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
return true;
}
do {
//获取锁解锁时间
String currentValue = (String)redisTemplate.opsForValue().get(key);
//如果锁过期
if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
//获得上一个锁的时间
String olcValue = (String)redisTemplate.opsForValue().getAndSet(key, value);
if (!StringUtils.isEmpty(olcValue) && olcValue.equals(currentValue)) {
return true;
}
}
try {
// log.info("等待500 ms key:{},value:{},cur:{}, 剩余:{}",key,value, System.currentTimeMillis(), Long.parseLong(value)-System.currentTimeMillis());
Thread.sleep(500);
} catch (InterruptedException e) {
}
}while(Long.parseLong(value) > System.currentTimeMillis());
return false;
}
/**
* 解锁
*
* @param key
* @param value
*/
public static void unlock(String key, long currvalue) {
try {
String value = currvalue+lockTimeout+"";
String currentVlue = (String)redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(currentVlue) && currentVlue.equals(value)) {
redisTemplate.opsForValue().getOperations().delete(key);
}
} catch (Exception e) {
log.error("【redis分布式锁】 解锁异常" + e.getMessage(), e);
}
}
}
测试:
@Test
public void testRedisLock() {
String key = "testRedisLock";
for (int i=0;i<100;i++) {
long currvalue = System.currentTimeMillis();
try {
System.out.println(i + "A="+ RedisLockUtil.lock(key, currvalue));
System.out.println("做了些事情开始。。");
// try {
// Thread.sleep(4000);
// } catch (InterruptedException e) {}
System.out.println("做了些事情结束。。");
}
finally {
currvalue = System.currentTimeMillis();
System.out.println(i + "B="+ RedisLockUtil.lock(key, currvalue));
RedisLockUtil.unlock(key, currvalue);
System.out.println(i + "C="+ RedisLockUtil.lock(key, currvalue));
}
}
}