版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
package com.example.demo.redis;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import java.util.Collections;
/**
* @Author Xiao HE
* @Create Time 2019/9/2 16:33
**/
@Component
public class RedisTool {
//Redis 执行成功返回
private static final String LOCK_SUCCESS = "OK";
// NX是不存在时才set, XX是存在时才set, EX是秒,PX是毫秒
private static final String SET_IF_NOT_EXIST = "NX";
// 设置 过期时间类型 EX = 秒 PX = 毫秒
private static final String SET_WITH_EXPIRE_TIME = "EX";
/**
* 尝试获取分布式锁
* @param jedis Redis客户端
* @param lockKey 锁
* @param requestId 请求标识
* @param expireTime 超期时间
* @return 是否获取成功
*/
public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
private static final Long RELEASE_SUCCESS = 1L;
/**
* 释放分布式锁
* @param jedis Redis客户端
* @param lockKey 锁
* @param requestId 请求标识
* @return 是否释放成功
*/
public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
}
package com.example.demo.MyTest;
import com.example.demo.redis.RedisTool;
import com.example.demo.service.UserService;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import lombok.Data;
import org.apache.logging.log4j.util.Strings;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static redis.clients.jedis.Protocol.Command.EXPIRE;
/**
* @Author Xiao HE
* @Create Time 2019/8/30 21:41
**/
@SpringBootTest
@RunWith(SpringRunner.class)
public class MyTest2 {
@Value("${spring.redis.host}")
public static String host;
static boolean isOpenExpirationRenewal = true;
public static void main(String[] args) throws Exception{
Jedis jedis = new Jedis(host);
String lockKey = "zhendifan";
String lockValue = UUID.randomUUID().toString();
//设置过期时间未 120 秒
boolean redisBoolean = RedisTool.tryGetDistributedLock(jedis, lockKey, lockValue, 120);
if(redisBoolean){
System.out.println("拿到redis 锁 进入方法");
Thread thread = new Thread(new ExpirationRenewal(jedis, lockKey, lockValue));
thread.start(); //启动线程
try{
System.out.println("逻辑代码执行中.........");
//假设需要执行两分钟
Thread.sleep(120000);
}catch (Exception e){
throw new Exception("发生异常!异常信息"+e);
}finally {
// 关闭线程
isOpenExpirationRenewal=false;
thread.interrupt();
//释放Redis 锁
RedisTool.releaseDistributedLock(jedis,lockKey,lockValue);
}
}
}
/*
* 刷新Key 过期时间 保证业务处理时间大于过期时间
* @param jedis Redis客户端
* @@param lockKey 锁
* @param requestId 请求标识
* */
@Data
public static class ExpirationRenewal implements Runnable{
private Jedis jedis;
private String lockKey;
private String lockValue;
public ExpirationRenewal(Jedis jedis, String lockKey, String lockValue) {
this.jedis = jedis;
this.lockKey = lockKey;
this.lockValue = lockValue;
}
@Override
public void run(){
//监测 锁过期时间
while (isOpenExpirationRenewal){
System.out.println("执行延迟失效时间中...");
String checkAndExpireScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('expire',KEYS[1],ARGV[2]) " +
"else " +
"return 0 end";
// 锁过期后重新给锁设置过期时间 15 秒
jedis.eval(checkAndExpireScript, 1, this.lockKey, this.lockValue, "15");
//如果不行 就直接Set 去重新设置过期时间
try {
//休眠10秒
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}