前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis实现分布式锁

Redis实现分布式锁

作者头像
zeekling
发布2022-08-26 19:58:45
2480
发布2022-08-26 19:58:45
举报

Redis被经常用来实现分布式锁,本文主要讲述redis如何实现一个分布式锁的demo。

获取锁

redis分布式锁的实现主要是通过redis的set命令实现:

代码语言:javascript
复制
SET key value nx PX milliseconds
  • nx : 当key存在的时候才将set对应的key,value写入到redis数据库里面。如果设置成功之后,就返回OK,已经存在就返回nil,当前set命令也是一个原子操作,可以作为分布式锁。
  • px milliseconds: 为当前key设置过期时间,当时间过了之后会将当前key删除。主要是方式获取锁之后未正常释放,导致死锁,一直无法获取锁。超时时间需要合理设置,需要保证当前业务能够处理完。
代码语言:javascript
复制
private static final String LOCK_SUCCESS = "OK";

  private static final Long UNLOCK_SUCCESS = 1L;

  //
  private static final String UNLOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

  private final JedisCluster cluster;

  private final long lockTimeout;

  private final String lockKey;

  public RedisDistributedLockImpl(JedisCluster cluster, String lockKey, long lockTimeout) {

    this.cluster = cluster;
    this.lockTimeout = lockTimeout;
    this.lockKey = lockKey;
  }

  @Override
  public String lock() {
    long end = System.currentTimeMillis() + lockTimeout;
    String requireToken = String.valueOf(System.currentTimeMillis());
    int expireTime = 300 * 1000;
    SetParams params = new SetParams().nx().px(expireTime);
    while (System.currentTimeMillis() < end) {
      try {
        String result = cluster.set(lockKey, requireToken, params);
        if (LOCK_SUCCESS.equals(result)) {
          System.out.println("lock success");
          return requireToken;
        }
        System.out.println("lock failed trying");
        Thread.sleep(100);
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      } catch (Exception e) {
        e.printStackTrace();
        return null;
      }
    }
    return requireToken;
  }

释放锁

释放锁,主要是需要通过原子操作将锁对应的key删除,可以通过下面lua脚本删除。

代码语言:javascript
复制
if redis.call('get', KEYS[1]) == ARGV[1] then 
   return redis.call('del', KEYS[1]) 
else 
    return 0 
end

释放锁的详细代码:

代码语言:javascript
复制
@Override
  public boolean unlock(String identify) {
    if (identify == null || identify.trim().length() == 0) {
      return false;
    }
    Object obj = new Object();
    try {
      obj = cluster.eval(UNLOCK_SCRIPT, Collections.singletonList(lockKey), Collections.singletonList(identify));
      if (UNLOCK_SUCCESS.equals(obj)) {
        System.out.println("release lock success, requestToken:" + identify);
        return true;
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    System.out.println("release lock failed, requestToken:" + identify + ", result:" + obj);
    return false;
  }

测试分布式锁

使用下面代码模拟秒杀场景:

代码语言:javascript
复制
public class RedisDistributedLockTest {

  static int n = 500;

  public static void secKill() {
    System.out.println("商品数量:" + --n);
  }

  public static void main(String[] args) {
    Runnable runnable = () -> {
      RedisDistributedLockImpl lock = null;
      String unLockIdentify = null;
      try {
        Set<HostAndPort> set = new HashSet<>();
        set.add(new HostAndPort("127.0.0.1", 30001));
        JedisPoolConfig config = new JedisPoolConfig();
        JedisCluster cluster = new JedisCluster(set, config);
        lock = new RedisDistributedLockImpl(cluster, "test1", 20000);
        unLockIdentify = lock.lock();
        System.out.println(Thread.currentThread().getName() + "正在运行");
        secKill();
      } finally {
        if (lock != null) {
          lock.unlock(unLockIdentify);
        }
      }
    };
    System.out.println("------------------开始--------------");
    for (int i = 0; i < 100; i++) {
      Thread t = new Thread(runnable);
      t.start();
    }
  }

}

执行结果如下:

image.png
image.png
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022.01.09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 获取锁
  • 释放锁
  • 测试分布式锁
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档