public interface DistributeLock {
/**
* 获取分布式锁,没有获取成功,阻塞直到默认超时
*/
boolean lock(String key);
/**
* 获取分布式锁,没有获取成功,阻塞直到超时
* @param timeout
*/
boolean lock(String key,int timeout);
/**
* 释放锁
*/
void release(String key);
}
package com.amarsoft.sea.processor.icdata.icalter.yszx.Timer;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.amarsoft.sea.utils.RedisUtils;
/**
* 基于redis实现的分布式锁
*/
@Component
public class RedisDistributeLock implements DistributeLock {
private final String LOCK_KEY_PREFIX = "hubservice.redislock.";
private final int DEFAULT_TIME_OUT = 2 * 60;
//设置过期时间,以防一个服务挂掉,不会释放锁
@Autowired
private RedisUtils redisUtils;
@Override
public boolean lock(String key) {
return doLock(key, DEFAULT_TIME_OUT);
}
@Override
public boolean lock(String key,int timeout) {
return doLock(key, timeout);
}
private boolean tryLock(String key,int timeout) {
List<String> keys = Arrays.asList(key);
List<String> args = Arrays.asList(String.valueOf(timeout));
String luaScript = createLuaScript();
Object result = redisUtils.executeLua(luaScript, keys, args);
if (result == null) {
return false;
}
String value = result.toString().trim();
return value.equals("1") ? true : false;
}
private boolean doLock(String key,int timeout) {
String lockKey = LOCK_KEY_PREFIX + key;
return tryLock(lockKey, timeout);
}
@Override
public void release(String key) {
String lockKey = LOCK_KEY_PREFIX + key;
redisUtils.remove(lockKey);//释放锁的最佳方式就是删除它
}
private String createLuaScript() {
String luaScript = "" +
"local lockKey = KEYS[1];\n" +
"local timeout = ARGV[1];\n" +
"if (redis.call('exists',lockKey) == 0) then \n" +
" redis.call('setex',lockKey,timeout,'1');\n" +
" return 1;\n" +
"else \n" +
" return 0;\n" +
"end \n";
return luaScript;
}
}
package com.amarsoft.sea.processor.icdata.icalter.yszx.Timer;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.amarsoft.sea.dao.crsbjt.ICTaskRepository;
import com.amarsoft.sea.entity.crsbjt.ICTask;
import com.amarsoft.sea.processor.icdata.icalter.yszx.EntICAlterYszx;
@Component
public class ScheduledExecutorService2ICAlterYszx {
private final static Logger LOGGER = LoggerFactory.getLogger(ScheduledExecutorService2ICAlterYszx.class);
@Autowired
private ICTaskRepository ICTaskRep;
@Autowired
private EntICAlterYszx entICAlterYszx;
@Autowired
private RedisDistributeLock lock;
@Value("${seaservice.period:20}")
private long time;
@PostConstruct
public void init() {
LOGGER.info("定时任务已启动...");
ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
service.scheduleAtFixedRate(new processTask(), 1, time, TimeUnit.MINUTES);
}
private class processTask implements Runnable{
@Override
public void run() {
//加锁
String key = "ic.alter.fail.retry";
try {
boolean flag = lock.lock(key);
if (!flag) {
return;
}
List<ICTask> iCTask = ICTaskRep.findFailStatus();
JSONArray array = new JSONArray();
iCTask.forEach(result -> {
array.add(JSONObject.parseObject(result.getAttribute2()));
});
if(array.size() > 0){
JSONObject jsonObject = new JSONObject();
jsonObject.put("count", String.valueOf(array.size()));
jsonObject.put("data", array);
entICAlterYszx.processMsg(jsonObject.toJSONString());
}
}catch (Throwable e) {
LOGGER.error("重试机制消费失败消息出错!!!",e);
} finally {
lock.release(key);
}
}
}
}
package com.amarsoft.sea.utils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.*;
/**
* redis 工具类
*/
@Component("redisUtils")
public class RedisUtils {
private volatile JedisSentinelPool pool;
@Value("${redis.sentinels.hosts}")
private String sentinelHosts;
@Value("${redis.maxActive}")
private Integer maxActive;
@Value("${redis.maxIdel}")
private Integer maxIdel;
@Value("${redis.maxWait}")
private Integer maxWait;
@Value("${redis.testOnBorrow}")
private boolean testOnBorrow;
@Value("${redis.masterName}")
private String masterName;
@Value("${redis.keyExpire:600}")
private Integer keyExpireTime;
@PostConstruct
public void init() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(maxActive);
poolConfig.setMaxIdle(maxIdel);
poolConfig.setMaxWaitMillis(maxWait);
poolConfig.setTestOnBorrow(testOnBorrow);
Set<String> sentinels = new HashSet<String>();
sentinels.addAll(Arrays.asList(sentinelHosts.split(",")));
pool = new JedisSentinelPool(masterName,sentinels,poolConfig);
}
public String get(String key) {
Jedis jedis = null;
try {
jedis = pool.getResource();
return jedis.get(key);
}finally {
if (jedis != null) {
jedis.close();
}
}
}
public void set(String key,String value) {
Jedis jedis = null;
try {
jedis = pool.getResource();
jedis.setex(key,keyExpireTime,value);
}finally {
if (jedis != null) {
jedis.close();
}
}
}
public void remove(String key) {
Jedis jedis = null;
try {
jedis = pool.getResource();
jedis.del(key);
}finally {
if (jedis != null) {
jedis.close();
}
}
}
public void incr(String key) {
Jedis jedis = null;
try {
jedis = pool.getResource();
jedis.incr(key);
jedis.expire(key,keyExpireTime);
}finally {
if (jedis != null) {
jedis.close();
}
}
}
public void hmset(String key,Map<String,String> hash) {
Jedis jedis = null;
try {
jedis = pool.getResource();
jedis.hmset(key,hash);
jedis.expire(key,keyExpireTime);
}finally {
if (jedis != null) {
jedis.close();
}
}
}
public String hmget(String key,String field) {
Jedis jedis = null;
try {
jedis = pool.getResource();
List<String> list = jedis.hmget(key,field);
if (list == null || list.size() == 0) {
return null;
} else {
return list.get(0);
}
}finally {
if (jedis != null) {
jedis.close();
}
}
}
public Map<String,String> hmget(String key,String ...fields) {
Jedis jedis = null;
try {
jedis = pool.getResource();
List<String> list = jedis.hmget(key,fields);
Map<String,String> map = new HashMap<String,String>();
for (int i = 0; i < fields.length; i++) {
map.put(fields[i],list.get(i));
}
return map;
}finally {
if (jedis != null) {
jedis.close();
}
}
}
public Object executeLua(String luaScript,List<String> keys,List<String> args) {
Jedis jedis = null;
try {
jedis = pool.getResource();
return jedis.eval(luaScript,keys,args);
}finally {
if (jedis != null) {
jedis.close();
}
}
}
public boolean hexists(String key,String field) {
Jedis jedis = null;
try {
jedis = pool.getResource();
return jedis.hexists(key,field);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
public boolean exists(String key) {
Jedis jedis = null;
try {
jedis = pool.getResource();
return jedis.exists(key);
}finally {
if (jedis != null) {
jedis.close();
}
}
}
@PreDestroy
public void close(){
if (pool != null) {
pool.close();
}
}
}