Redis实现分布式锁机制

本文介绍如何使用Redis实现分布式锁,包括使用Lua脚本和Redisson框架两种方法。Lua脚本实现简单,直接调用eval方法执行加锁和解锁操作;Redisson框架提供更高级的API,简化了锁的管理和使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Redis实现分布式锁思路
  常用的是redis函数是setnx(),这个应该是实现分布式锁最主要的函数。首先是将某一业务标识名作为键存到redis里,并为其设个过期时间,如果是还有加锁请求过来,先是通过setnx()看看是否能将锁的标识插入到redis里,可以的话就返回true,不可以就返回false。
  
一、使用Lua脚本简单的实现Redis锁的实现 :

public class DistributeLocker {

    private Jedis jedis;

    private Lock lock;
	/**
	 * 加锁成功标识
	 */
    private static final String LOCK_SUCCESS = "1";
	/**
	 * 脚本入参个数
	 */
    private static final int KEY_COUNT = 1;
	/**
	 * 加锁脚本
	 */
    private static String LOCK_SCRIPT;
	/**
	 * 解锁脚本
	 */
    private static String RELEASE_SCRIPT;
	/**
	 * 初始化脚本
	 */
    static {
        LOCK_SCRIPT = "local key = redis.call('get',KEYS[1]) if ('1' == key) then return 0 "
                + "else redis.call('set',KEYS[1],'1') redis.call('expire',KEYS[1],ARGV[1]) return 1 end";
        RELEASE_SCRIPT = "if (redis.call('exists',KEYS[1])) then redis.call('del',KEYS[1]) end";
    }
    /**
	 * 定义带参构造函数
	 */
    public DistributeLocker (Lock lock) { }
    public void lock (final String key, final int exprieTime) {
    	try {
	        if (LOCK_SUCCESS.equals(jedis.eval(LOCK_SCRIPT, KEY_COUNT, key, String.valueOf(exprieTime)))) {
	            lock.success();
	        } else {
	            lock.failure();
	        }
        } finally {
        	releaseLock(key);
        }
    }
	
	/**
	 * 解锁逻辑
	 */
    public void releaseLock (String key) {
        jedis.eval(RELEASE_SCRIPT, KEY_COUNT, key);
    }
}


public interface Lock {

    void success();

    void failure();
}
public class Test {

    void purchase(String key, int secondTime){
        new DistributeLocker(new Lock() {
            @Override
            public void success() {
                // do something
            }

            @Override
            public void failure() {
                // do something
            }
        }).lock(key,secondTime);
    }
}

注:Redis分布式锁的实现方式有很多种,各有利弊,加锁的时候主要注意检查锁与加锁操作要有原子性,防止重复加锁成功。过期时间主要是为了防止未释放锁导致锁的一直存在,从而无法获取锁操作。

二、使用Redisson框架

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.13.0</version>
</dependency>
  • 使用缺省配置

  • 工具类

@Slf4j
@Component
public class DistributeLocker {

    private RedissonClient redissonClient;

    public DistributeLocker(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    public void lock (String key, long exprieTime, LockTask task) {
        lock(0L, key, exprieTime, task);
    }

    public void lock (long waitTime, String key, long exprieTime, LockTask task) {
        RLock rLock = redissonClient.getLock(key);
        try {
            if (rLock.tryLock(waitTime, exprieTime, TimeUnit.MILLISECONDS)) {
                task.success();
            } else {
                task.failure();
            }
        } catch (Exception e) {
            log.error("DistributeLocker.lock Error. key:{}, e:{}", key, e);
        } finally {
            rLock.unlock();
        }
    }

}

  • 使用
@SpringBootApplication
@EnableDiscoveryClient
public class StartUpApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(StartUpApplication.class, args);
        DistributeLocker locker = context.getBean(DistributeLocker.class);
        locker.lock("test", 100L, new LockTask() {
            @Override
            public void success() {
                System.out.println("加锁成功");
            }

            @Override
            public void failure() {
                System.out.println("加锁失败");
            }
        });
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值