标签:
多节点的部署中,对锁的控制,参考:
http://www.jeffkit.info/2011/07/1000/
直接贴上代码实现,同上一篇文章一样,都是基于AOP
定义注解,标志切入点:
package com.ns.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface RedisLock { /** * redis的key * @return */ String value(); /** * 持锁时间,单位毫秒,默认一分钟 */ long keepMills() default 60000; /** * 当获取失败时候动作 */ LockFailAction action() default LockFailAction.GIVEUP; public enum LockFailAction{ /** * 放弃 */ GIVEUP, /** * 继续 */ CONTINUE; } /** * 睡眠时间,设置GIVEUP忽略此项 * @return */ long sleepMills() default 1000; }
切面实现:
package com.ns.redis.aop; import java.lang.reflect.Method; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.ns.annotation.RedisLock; import com.ns.annotation.RedisLock.LockFailAction; import com.ns.redis.dao.base.BaseRedisDao; @Aspect public class RedisLockAspect extends BaseRedisDao<String, Long>{ private static final Logger log = LoggerFactory.getLogger(RedisLockAspect.class); //execution(* com.ns..*(*,..)) and @within(com.ns.annotation.RedisLock) @Pointcut("execution(* com.ns..*(..)) && @annotation(com.ns.annotation.RedisLock)") private void lockPoint(){} @Around("lockPoint()") public Object arround(ProceedingJoinPoint pjp) throws Throwable{ MethodSignature methodSignature = (MethodSignature) pjp.getSignature(); Method method = methodSignature.getMethod(); RedisLock lockInfo = method.getAnnotation(RedisLock.class); boolean lock = false; Object obj = null; while(!lock){ long timestamp = System.currentTimeMillis()+lockInfo.keepMills(); lock = setNX(lockInfo.value(), timestamp); //得到锁,已过期并且成功设置后旧的时间戳依然是过期的,可以认为获取到了锁(成功设置防止锁竞争) long now = System.currentTimeMillis(); if(lock || ((now > getLock(lockInfo.value())) && (now > getSet(lockInfo.value(), timestamp)))){ //得到锁,执行方法,释放锁 log.info("得到锁..."); obj = pjp.proceed(); //不加这一行,对于只能执行一次的定时任务,时间差上不能保证另一个一定正好放弃 if(lockInfo.action().equals(LockFailAction.CONTINUE)){ delete(lockInfo.value()); } }else{ if(lockInfo.action().equals(LockFailAction.CONTINUE)){ log.info("稍后重新请求锁..."); Thread.currentThread().sleep(lockInfo.sleepMills()); }else{ log.info("放弃锁..."); break; } } } return obj; } public boolean setNX(String key,Long value){ return valueOperations.setIfAbsent(key, value); } public long getLock(String key){ return valueOperations.get(key); } public Long getSet(String key,Long value){ return valueOperations.getAndSet(key, value); } public void releaseLock(String key){ delete(key); } }
以上有些代码只符合我现在的项目场景,根据实际需要进行调整
深入理解Spring Redis的使用 (九)、通过Redis 实现 分布式锁
标签:
原文地址:http://www.cnblogs.com/luochengqiuse/p/4796364.html