使用RedisTemplate实现分布式乐观锁

前言

使用乐观锁能够在不上锁的情况下实现线程安全,常用的实现方式就是使用CAS自旋的形式实现。

通常在分布式系统中有三种实现方式

数据库行级锁
Zookeeper实现分布锁
Redis实现乐观锁

三种方式各有优点,其中Redis和Zookeeper最常用,Redis性能最高,Zookeeper可靠性最高

代码实现

基于RedisTemplate,封装使用,通过IOC控制的方式实现:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * Redis的分布式锁工具类
 * 利用 setnx 实现乐观锁
 *
 * @author smoyu
 * @Date 2021-08-08 21:50:16
 */

@Component
public class RedisTemplateUtil {

    // 锁名称 prefix expire 锁对象
    public static final String LOCK_PREFIX = "RedisLock";
    // 加锁失效时间,毫秒,通常是业务执行时间的3-5倍
    public static final int LOCK_EXPIRE = 2000;
    // 轮询次数 根据项目而定
    public static final int COUNT = 20;
    // 轮询间隔时间  一般在50-100ms,根据项目而定
    public static final int INTERVAL = 50;


    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 加锁操作
     * 
	 * @author smoyu
     * @param key 锁的名称
     * @return
     */
    public Boolean setLock(String key) {
        return redisTemplate.opsForValue().setIfAbsent(key, LOCK_PREFIX, LOCK_EXPIRE, TimeUnit.MILLISECONDS);
    }

    /**
     * 释放锁
	 * @author smoyu
     * @return true or false
     */
    public Boolean deleteLock(String key) {
        return redisTemplate.delete(key);
    }


    /**
     * 采用轮询的方式去加锁,轮询次数和轮询间隔时间写死
     * 尝试去获得锁
     *
     * @param key
     * @return
     */
    public Boolean tryCasLock(String key) {
        int count = COUNT;//获取总轮询次数
        while (count > 0) {
            count--;
            if (setLock(key)) {
                return true;
            } else {
                try {
                    Thread.sleep(INTERVAL);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    throw new RuntimeException(false, StatusCode.ERROR, "服务器繁忙,请稍后再试。");
                }
            }
        }
        //如果一直没有取得锁,就返回false
        return false;
    }


}

使用:调用tryCasLock上锁,deleteLock解锁,解锁操作放在finnally

@Service
public class OrderServiceImpl implements OrderService {

    //分布式锁
    @Autowired
    private RedisTemplateUtil redisLockUtils;


    /**
     * 抢单
     *
     * @param order
     */
    @Override
    public void add() {
  
        //分布式锁,解决超额抢单问题
        if (redisLockUtils.tryCasLock(courseId + "")) {
          	try{
          	//这里写业务
            } finally {
                //释放锁
                redisLockUtils.deleteLock(courseId + "");
            }
        }

    }


}

你可能感兴趣的:(分布式,Redis,Java,java,spring,分布式锁)