redis分布式锁、公平锁、spring、redis消息订阅

1-maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2-配置yml....省略

3-分布式公平锁注解



import com.alibaba.fastjson2.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.stereotype.Component;

import java.lang.annotation.*;
import java.util.*;
import java.util.concurrent.locks.LockSupport;


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Order(10)
public @interface RedisLock {

String value() default "redis_lock_order";//锁的名称



String[] keys() default {};//字段,最终锁的名称=>(value_key)

/**
* 最大持有锁时间,如果超过该时间仍未主动释放,将自动释放锁。
* (这个时间要大于redis的超时断开链接的时间)
*
* @return 最大持有锁时间 秒
*/
int lockTime() default 10;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
class RedisLockAspect {

// redis分布式锁的 消息订阅得服务器标识
public final static String lock_this_sys_name = UUID.randomUUID().toString().replace("-", "");

private final StringRedisTemplate stringRedisTemplate;
protected static boolean redisDeleteThread = false;
protected static final String lockname = "locknames:";

protected void deleteRedisLock() {
if (!redisDeleteThread) {
synchronized ("threadredisdelete") {
if (!redisDeleteThread) {
log.info("启动分布式锁检测程序");
deleteRedisLock1();
new Thread(() -> {
while (true) {
LockSupport.parkNanos(1000000000l);
try {
deleteRedisLock1();
} catch (Exception e) {
}
}
}, "分布式锁检测程序").start();
redisDeleteThread = true;
}
}
}
}


protected void deleteRedisLock1() {
long redisTime = currentTimeMillis().longValue();
Set<String> keys = stringRedisTemplate.keys(lockname + "*");
for (String key : keys) {
List<String> vals = stringRedisTemplate.opsForList().range(key, 0, -1);
for (String val : vals) {
Map map = JSON.parseObject(val, HashMap.class);
long createTime = Long.parseLong(map.get("redisCreateTime").toString());
long lockTime = Long.parseLong(map.get("lockTime").toString());
if (createTime + (lockTime * 1000) < redisTime) {
Long remove = stringRedisTemplate.opsForList().remove(key, 1, val);
if (0 < remove) {
log.info("删除过期锁(" + key + "):" + val);
}
}
}
}
}

@Pointcut("@annotation(RedisLock)")
public void rlockaspect() {
}


@Around("rlockaspect()")
public Object aroundRemote(ProceedingJoinPoint jp) throws Throwable {
RedisLock rc = ((MethodSignature) jp.getSignature()).getMethod().getAnnotation(RedisLock.class);

String rediskey_name = rc.value();
if (rc.keys() != null && rc.keys().length > 0) {
for (String key : rc.keys()) {
String[] parameters = ((MethodSignature) jp.getSignature()).getParameterNames();
Object[] args = jp.getArgs();
for (int i = 0; i < parameters.length; i++) {
if (parameters[i].equals(key)) {
rediskey_name += ":"+key+"="+args[i];
}
}
}
}
deleteRedisLock();
String rediskey = lockname + rediskey_name;
Map map = new HashMap();
map.put("lock_sys_name", lock_this_sys_name);
map.put("uid", UUID.randomUUID().toString().replaceAll("-", ""));
map.put("threadid", Thread.currentThread().getId());
map.put("redisCreateTime", currentTimeMillis());
map.put("lockTime", rc.lockTime());
String redis_values = JSON.toJSONString(map);
stringRedisTemplate.opsForList().rightPush(rediskey, redis_values);
boolean dengdai = true;
while (true) {
String redis_sysinfo = stringRedisTemplate.opsForList().index(rediskey, 0);
if (redis_values.equals(redis_sysinfo)) {
try {
return jp.proceed();
} finally {
stringRedisTemplate.opsForList().remove(rediskey, 1, redis_values);
String next_redis_msg = stringRedisTemplate.opsForList().index(rediskey, 0);
if (null != next_redis_msg) {
Map hashMap = JSON.parseObject(next_redis_msg, HashMap.class);
if (null != hashMap) {
Object o = hashMap.get("lock_sys_name");
if (null != o) {
stringRedisTemplate.convertAndSend(o.toString(), next_redis_msg);
}
}
}
}
} else {
if (dengdai) {
dengdai = false;
LockSupport.parkNanos(rc.lockTime() * 1000000000l);
} else {
stringRedisTemplate.opsForList().remove(rediskey, 1, redis_values);
break;
}
}
}
throw new RuntimeException(rediskey + "锁超时, 请稍等再试");
}

// 接收到redis 向所有人发送的 订阅消息
// 处理redis 锁消息
public void readRedisLockMsg(String message) {
Map hashMap = JSON.parseObject(message, HashMap.class);
Object o_lock_sys_name = hashMap.get("lock_sys_name");
if (null != o_lock_sys_name && o_lock_sys_name.toString().equals(lock_this_sys_name)) {
Object o_threadid = hashMap.get("threadid");
if (o_threadid != null) {
Thread thread = findThread(Long.parseLong(o_threadid.toString()));
if (null != thread) {
LockSupport.unpark(thread);
}
}
}
}

@Bean
RedisMessageListenerContainer setRedislockFactory(RedisMessageListenerContainer container, MessageListenerAdapter readRedisLockMsgBean) {
//listenerAdapter 参数名和 方法名相同
container.addMessageListener(readRedisLockMsgBean, new PatternTopic(lock_this_sys_name));
return container;
}

//监听分布式锁程序,此方法名字要和container.addMessageListener(名字,...) 此名字相同
@Bean
MessageListenerAdapter readRedisLockMsgBean(RedisLockAspect receiver) {
return new MessageListenerAdapter(receiver, "readRedisLockMsg");
}

protected static final String SCRIPT_TIME = "local a=redis.call('TIME'); return (a[1]*1000000+a[2])/1000";

/**
* 获取当前时间戳,13位
*/
public Long currentTimeMillis() {
final DefaultRedisScript<Long> script = new DefaultRedisScript<>(SCRIPT_TIME, Long.class);
return stringRedisTemplate.execute(script, Collections.EMPTY_LIST);
}

/**
* 通过线程组获得线程
*/
public static Thread findThread(long threadId) {
ThreadGroup group = Thread.currentThread().getThreadGroup();
while (group != null) {
Thread[] threads = new Thread[(int) (group.activeCount() * 1.2)];
int count = group.enumerate(threads, true);
for (int i = 0; i < count; i++) {
if (threadId == threads[i].getId()) {
return threads[i];
}
}
group = group.getParent();
}
return null;
}



}
}



posted @   Mr·柯  阅读(226)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示