实际开发中,当系统是分布式集群情况下,多个请求对一条数据进行更新时,为了数据安全,我们必须要将这条数据锁住,但是集群负载情况下使用jdk自带的锁此时已经无济于事。我们必须要使用数据库锁。下面是基于redis实现的分布式锁简单案例。

1、锁接口

/**
 * 分布式锁
 * @author zhanglei
 */
public interface YBLock {

    /**
     * 获取锁
     * @return  boolean
     */
    boolean acquire();


    /**
     * 释放锁
     */
    void  release();
}

2、回调接口

/**
 * 获取锁失败,回调接口
 *
 * @author zhanglei
 */
public interface LockBack {


    void  fallback(RedisLock redisLock);
}

3、redis锁实现

/**
 * redis分布式锁实现
 *
 * 锁本身并不是线程安全的,使用请在函数内部创建新的锁实例使用。
 *
 * @author zhanglei
 */
@SuppressWarnings("unchecked")
public class RedisLock implements YBLock{

    private static Logger logger = LoggerFactory.getLogger(RedisLock.class);

    /**
     * redisTemplate
     */
    private RedisTemplate redisTemplate;

    /**
     * 获取锁失败,回调
     */
    private LockBack lockBack;

    /**
     * 锁字符串
     */
    private String lockKey;

    /**
     * 锁过期时间  默认10秒  放置程序故障导致的锁永久不释放 单位毫秒
     */
    private  int  expireTime = 1000 * 10;

    public RedisLock(String lockKey){
        this.lockKey = lockKey;
        synchronized (RedisLock.class){
            if(redisTemplate == null){
                redisTemplate = SpringContext.getBean(StringRedisTemplate.class);
            }
        }
    }

    public RedisLock(String lockKey,int expireTime){
        this(lockKey);
        this.expireTime = expireTime;
    }

    public RedisLock(String lockKey,int expireTime,LockBack lockBack){
        this(lockKey,expireTime);
        this.lockBack = lockBack;
    }

    public RedisLock(String lockKey, LockBack lockBack){
        this(lockKey);
        this.lockBack = lockBack;
    }

    /**
     * 获取锁
     */
    @Override
    public boolean acquire() {

        //过期时间值
        String  expire = Long.toString(System.currentTimeMillis() + this.expireTime);

        try {
            while (true) {

                //在redis中设置值
                boolean acq = redisTemplate.opsForValue().setIfAbsent(this.lockKey, expire);

                //设置成功
                if (acq) {
                    logger.info("get redis lock success!");
                    //设置过期时间
                    redisTemplate.expire(this.lockKey, expireTime, TimeUnit.MILLISECONDS);
                    return true;
                }

                //如果获取锁失败,调用回调
                if (this.lockBack != null) {
                    this.lockBack.fallback(this);
                    return false;
                }


                //睡眠100毫秒
                Thread.sleep(100);
            }
        }catch (Exception e){
            logger.error(e.getMessage(),e);
        }
        return false;
    }

    /**
     * 释放锁
     */
    @Override
    public void release() {
        this.redisTemplate.delete(this.lockKey);
    }

    public String getLockKey() {
        return lockKey;
    }

    public void setLockKey(String lockKey) {
        this.lockKey = lockKey;
    }

    public int getExpireTime() {
        return expireTime;
    }

    public void setExpireTime(int expireTime) {
        this.expireTime = expireTime;
    }

}

4、获取锁工具类

/**
 * 获取锁
 */
public final class LockUtil {

    private static final String  LOCK_KEY_NULL = "lock key not null";

    private LockUtil(){}

    public static RedisLock  getLock(String lockKey){
        Assert.notEmpty(LOCK_KEY_NULL,lockKey);
        return new RedisLock(lockKey);
    }

    public static RedisLock  getLock(String lockKey,LockBack lockBack){
        Assert.notEmpty(LOCK_KEY_NULL,lockKey);
        return new RedisLock(lockKey,lockBack);
    }


    public static RedisLock  getLock(String lockKey,int expire){
        Assert.notEmpty(LOCK_KEY_NULL,lockKey);
        return new RedisLock(lockKey,expire);
    }

    public static RedisLock getLock(String lockKey,int expire,LockBack lockBack){
        Assert.notEmpty(LOCK_KEY_NULL,lockKey);
        return new RedisLock(lockKey,expire,lockBack);
    }
}

以上代码可以实现简单的分布式锁