Redis的分布式锁实现

分布式锁一般有三种实现方式:
1. 数据库乐观锁;
2. 基于Redis的分布式锁;
3. 基于ZooKeeper的分布式锁。 
分布式锁:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问
分布式锁的使用场景: 线程间并发问题和进程间并发问题都是可以通过分布式锁解决的,但是强烈不建议这样做!

分布式锁的实现(Redis)

几个要用到的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秒。

代码实现:

依赖引入:


    redis.clients
    jedis
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, “liqiyao”);
     }
 }

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;
         }
     }
 }

分布式锁工具类:

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;
             }
         }
     }
 }

加锁代码:

public class RedisTool {

    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";

    /**
     * 尝试获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }

}

解锁代码:

public class RedisTool {

    private static final Long RELEASE_SUCCESS = 1L;

    /**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {

        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }

}

基于redisson分布式锁

 配置文件:

       
            org.redisson
            redisson
            3.11.2
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
   @Autowired
    private RedissonClient redissonClient;

    @RequestMapping("/redissonLock")
    public String redissonLock() throws InterruptedException { 
   

        RLock rLock = redissonClient.getLock("order");
        log.info("我进入了方法");

        rLock.lock(30, TimeUnit.SECONDS);
        log.info("获得了锁");
        Thread.sleep(15000);
        log.info("释放了锁");
        rLock.unlock();
        log.info("方法执行完成");

        return "方法执行完成";
    }

你可能感兴趣的:(分布式,redis,java)