当前位置:海洋目录网 » 站长资讯 » 教育考试 » 文章详细 订阅RssFeed

基于单节点redis实现分布式锁

来源:本站原创 浏览:45次 时间:2022-12-08

使用redis实现分布式锁基本就2步:第一多线程请求处理获取锁时,使用setnx指令,只有当key不存在时才设值,注意设置超时时间。

set key value [expiration EX seconds|PX milliseconds] [NX|XX]

第二相关业务处理完成之后,谁加的锁应该由谁去及时释放,即删除指定的key,注意删除时要匹配加锁线程的value,避免因超时误删其它线程的锁,这里使用Lua脚本执行原子操作,也可以先判断key value再del。

if redis.call("get",KEYS[1]) == ARGV[1] then
 return redis.call("del",KEYS[1])
else
 return 0
end

----

下面使用单节点redis,redis版本5.0.8,版本客户端使用jedis3.2.0,完成相关加锁,释放锁的操作。

<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>3.2.0</version>
</dependency>

注意使用jedisPool时默认最大连接数是8,使用完记得关闭连接,否则会造成线程等待,set成功时返回"OK",lua脚本删除成功时,返回"1"。

public boolean lock(String key, String value, long waitTimeOut, SetParams params) {
   Jedis jedis = null;

   try {

    jedis = JedisPool.getResource();
       long

       long start = System.currentTimeMillis();
       for (; ; ) {
           String lock = jedis.set(key, value, params);
           if ("OK".equals(lock)) {
               return true;
           }
           long wait = System.currentTimeMillis() - start;
           if (wait >= waitTimeOut) {
               return false;
           }
           try {
               Thread.sleep(100);
           } catch (InterruptedException e) {
               log.error("");
               return false;
           }
       }
   } catch (Exception e) {
       e.printStackTrace();
       return false;
   } finally {
       jedis.close();
   }
}
public boolean unlock(String key, String value) {
   Jedis jedis = null;
   try {
       jedis = JedisPool.getResource();
       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(key),
               Collections.singletonList(value));
       if ("1".equals(result.toString())) {
           return true;
       }
       return false;
   } catch (Exception e) {
       e.printStackTrace();
       return false;
   } finally {
       jedis.close();
   }
}

----

最后,在controller里简单测试一下锁的效果:

@GetMapping("hello")
public String hello() {
   String value = System.nanoTime() + "." + UUID.randomUUID();
   CountDownLatch latch = new CountDownLatch(1000);
   for (int i = 0; i < 1000; i++) {
       new Thread(() -> {
           redisLock.lock(KEY,value,1000,SetParams.setParams().nx().px(500000));
           amount--;
           System.out.println(Thread.currentThread() + ":" + amount);
           redisLock.unlock(KEY,value);
           latch.countDown();
       }).start();
   }
   try {
       latch.await();
   } catch (InterruptedException e) {
       e.printStackTrace();
   }
   return "amount:" + amount;
}

不加锁时多次执行会出现数据错误,添加锁后数据正常,可以使用专业的工具进行测试验证,这里为了等待所有线程执行完成使用了countDownLatch。

----

这里的分布式锁是基于redis单点完成的,使用单机可能会出现单节点故障。且锁是不可重入的。通常redis都是集群部署的,可以使用redission来完成集群redis的分布式锁操作,实现了redlock算法,且value关联线程,实现了锁的可重入。


  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net