码迷,mamicode.com
首页 > 编程语言 > 详细

深入理解Spring Redis的使用 (九)、通过Redis 实现 分布式锁

时间:2015-09-10 00:22:12      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:

多节点的部署中,对锁的控制,参考:

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!