基于redis集群实现的分布式锁,可用于秒杀,定时器。

在分布式系统中,经常会出现需要竞争同一资源的情况,使用redis可以实现分布式锁。

前提:redis集群已经整合项目,并且可以直接注入JedisCluster使用:

    @Autowired
    private JedisCluster jedisCluster;

 

1. 新建RedisLockManger分布式锁管理器,并且如上注入 JedisCluster :

package com.jarfk.util.redis;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisCluster;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * redis集群分布式锁管理器,支持对单个资源加锁解锁,或给一批资源的批量加锁及解锁
 * Created by Administrator on 2017/10/12 0012.
 */
@Component
public class RedisLockManger {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisLockManger.class);

    //设置3秒过期
    private static final int DEFAULT_SINGLE_EXPIRE_TIME = 3;

    //    private static final int DEFAULT_BATCH_EXPIRE_TIME = 6;

    //static的变量无法注解
    @Autowired
    private JedisCluster jc;

    private static RedisLockManger lockManger;

    public RedisLockManger() {
    }

    @PostConstruct
    private void init() {
        lockManger = this;
        lockManger.jc = this.jc;
    }
    /**
     * 获取锁 如果锁可用   立即返回true,  否则立即返回false,作为非阻塞式锁使用
     * @param key
     * @return
     */
    public boolean tryLock(String key/* , String value*/) {
        try {
            return tryLock(key, key, 0L, null);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 锁在给定的等待时间内空闲,则获取锁成功 返回true, 否则返回false,作为阻塞式锁使用
     * @param key 锁键
     * @param value 被谁锁定
     * @param timeout 尝试获取锁时长,建议传递500,结合实践单位,则可表示500毫秒
     * @param unit,建议传递TimeUnit.MILLISECONDS
     * @return
     * @throws InterruptedException
     */
    public boolean tryLock(String key , String value , long timeout , TimeUnit unit) throws InterruptedException {
        //纳秒
        long begin = System.nanoTime();
        do {
            //LOGGER.debug("{}尝试获得{}的锁.", value, key);
            Long i = lockManger.jc.setnx(key, value);
            if (i == 1) {
                lockManger.jc.expire(key, DEFAULT_SINGLE_EXPIRE_TIME);
                LOGGER.debug(value + "-成功获取{}的锁,设置锁过期时间为{}秒 ", key, DEFAULT_SINGLE_EXPIRE_TIME);
                return true;
            } else {
                // 存在锁 ,但可能获取不到,原因是获取的一刹那间
//                String desc = lockManger.jc.get(key);
//                LOGGER.error("{}正被{}锁定.", key, desc);
            } if (timeout == 0) {
                break;
            }
            //在其睡眠的期间,锁可能被解,也可能又被他人占用,但会尝试继续获取锁直到指定的时间
            Thread.sleep(100);
        } while ((System.nanoTime() - begin) < unit.toNanos(timeout));
        //因超时没有获得锁
        return false;
    }

    /**
     * 释放单个锁
     * @param key 锁键
     */
    public void unLock(String key/*, String value*/) {
        lockManger.jc.del(key);
        LOGGER.debug("{}锁被{}释放 .", key, key);
    }
}

 

2. 使用示例:

首先在需要加锁的地方注入分布式锁管理器:

    @Autowired
    private RedisLockManger redisLock;

然后调用即可,如:

        if (redisLock.tryLock("statusCheck")) { //此处代码是锁上的
            logger.debug("-----------------------:10秒执行一次!每次只有一个程序运行");
            //释放锁,正常情况下,此处代码要注释掉,以免锁被释放,需要释放时可以根据自己逻辑的需要 
            //redisLock.unLock("statusCheck");
        }

 

 

首先注入需要的

posted @ 2017-10-12 10:49  007少侠  阅读(5680)  评论(0编辑  收藏  举报
友情链接:便宜vps(CN2GIA线路)
站长统计: