分布式锁的作用及实现(Redis)

分布式锁用于解决多JVM环境下的并发问题,避免资源访问冲突。Redis是实现分布式锁的一种常见方式。实现关键点包括锁的超时机制和互斥访问。通过Redis的setnx、get、getset和expire等命令确保锁的安全性。本文介绍了使用Jedis API实现Redis分布式锁的详细步骤,包括创建连接池、封装API和构建分布式锁工具类。

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

分布式锁:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。

一、分布式锁的使用场景

如果是单机情况下(单JVM),线程之间共享内存,只要使用线程锁就可以解决并发问题。

如果是分布式情况下(多JVM),线程A和线程B很可能不是在同一JVM中,这样线程锁就无法起到作用了,这时候就要用到分布式锁来解决。

二、分布式锁的实现(Redis)

分布式锁实现的关键是在分布式的应用服务器外,搭建一个存储服务器,存储锁信息可以使用Redis。

在实现的时候要注意的几个关键点:

1、锁信息必须是会过期超时的,不能让一个线程长期占有一个锁而导致死锁;

2、同一时刻只能有一个线程获取到锁。

几个要用到的redis命令:

setnx(key, value):“set if not exits”,若该key-value不存在,则成功加入缓存并且返回1,否则返回0。

get(key):获得key对应的value值,若不存在则返回nil。

getset(key, value):先获取key对应的value值,若不存在则返回nil,然后将旧的value更新为新的value。

expire(key, seconds):设置key-value的有效期为seconds秒。

看一下流程图:

在这个流程下,不会导致死锁。

我采用Jedis作为Redis客户端的api,下面来看一下具体实现的代码。

(1)首先要创建一个Redis连接池。


public class RedisPool {
 
    private static JedisPool pool;//jedis连接池
 
    private static int maxTotal = 20;//最大连接数
 
    private static int maxIdle = 10;//最大空闲连接数
 
    private static int minIdle = 5;//最小空闲连接数
 
    private static boolean testOnBorrow = true;//在取连接时测试连接的可用性
 
    private static boolean testOnReturn = false;//再还连接时不测试连接的可用性
 
    static {
        initPool();//初始化连接池
    }
 
    public static Jedis getJedis(){
        return pool.getResource();
    }
 
    public static void close(Jedis jedis){
        jedis.close();
    }
 
    private static void initPool(){
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxTotal);
        config.setMaxIdle(maxIdle);
        config.setMinIdle(minIdle);
        config.setTestOnBorrow(testOnBorrow);
        config.setTestOnReturn(testOnReturn);
        config.setBlockWhenExhausted(true);
        pool = new JedisPool(config, "127.0.0.1", 6379, 5000, "zhoutao");
    }
}

(2)对Jedis的api进行封装,封装一些实现分布式锁需要用到的操作。

public class RedisPoolUtil {
 
    private RedisPoolUtil(){}
 
    private static RedisPool redisPool;
 
    public static String get(String key){
        Jedis jedis = null;
        String result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.get(key);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }
 
    public static Long setnx(String key, String value){
        Jedis jedis = null;
        Long result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.setnx(key, value);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }
 
    public static String getSet(String key, String value){
        Jedis jedis = null;
        String result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.getSet(key, value);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }
 
    public static Long expire(String key, int seconds){
        Jedis jedis = null;
        Long result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.expire(key, seconds);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }
 
    public static Long del(String key){
        Jedis jedis = null;
        Long result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.del(key);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }
}

(3)分布式锁工具类

public class DistributedLockUtil {
 
    private DistributedLockUtil(){
    }
 
    public static boolean lock(String lockName){//lockName可以为共享变量名,也可以为方法名,主要是用于模拟锁信息
        System.out.println(Thread.currentThread() + "开始尝试加锁!");
        Long result = RedisPoolUtil.setnx(lockName, String.valueOf(System.currentTimeMillis() + 5000));
        if (result != null && result.intValue() == 1){
            System.out.println(Thread.currentThread() + "加锁成功!");
            RedisPoolUtil.expire(lockName, 5);
            System.out.println(Thread.currentThread() + "执行业务逻辑!");
            RedisPoolUtil.del(lockName);
            return true;
        } else {
            //如果锁存在但是过期,执行加锁
            String lockValueA = RedisPoolUtil.get(lockName);
            if (lockValueA != null && Long.parseLong(lockValueA) <= System.currentTimeMillis()){
                String lockValueB = RedisPoolUtil.getSet(lockName, String.valueOf(System.currentTimeMillis() + 5000));
                if (lockValueB == null || lockValueB.equals(lockValueA)){
                    System.out.println(Thread.currentThread() + "加锁成功!");
                    RedisPoolUtil.expire(lockName, 5);
                    System.out.println(Thread.currentThread() + "执行业务逻辑!");
                    RedisPoolUtil.del(lockName);
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
    }
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值