使用复述,实现分布式锁的方法

  介绍

小编给大家分享一下使用复述,实现分布式锁的方法,希望大家阅读完这篇文章后大所收获、下面让我们一起去探讨吧!

使用复述,实现分布式锁

复述,特性介绍

1支持丰富的数据类型,如字符串,列表,地图,设置,ZSet等。

2支持数据持久化,RDB和AOF两种方式

3支持集群工作模式,分区容错性强

4,单线程,顺序处理命令

5支持事务

6支持发布与订阅

复述,实现分布式锁使用了SETNX命令:

SETNX键值将关键的值设为值,当且仅当关键不存在。

若给定的关键已经存在,则SETNX不做任何动作。

SETNX是“如果不存在”(如果不存在,则集)的简写。

可用版本:祝辞=1.0.0时间复杂度:O(1)返回值:

设置成功,返回1 .

设置失败,返回0。

redis>#工作存在工作不存在   (整数)0      redis>SETNX工作“programmer"#工作设置成功   (整数)1      redis>SETNX工作“code-farmer"#尝试覆盖工作,失败   (整数)0      redis>得到工作#没有被覆盖   “programmer"

首先,我们需要封装一个公共的复述,访问工具类。该类需要注入RedisTemplate实例和ValueOperations实例,使用ValueOperations实例是因为复述,实现的分布式锁使用了最简单的字符串类型。另外,我们需要封装3个方法,分别是setIfObsent(字符串,字符串值),到期(字符串键,长时间超时,TimeUnit unit)、删除(String键),分别对应复述的SETNX,到期,德尔命令。以下是复述,访问工具类的具体实现:

@ component   公开课RedisDao {      @ autowired   私人RedisTemplate RedisTemplate;      @ resource (name=皉edisTemplate")   私人ValueOperations<对象,Object>valOpsObj;/* *   *如果关键不存在,就存储一个键-值,相当于SETNX命令   * @param键键   * @param值值,可以为空   * @return   */公共布尔setIfObsent(字符串,字符串值){   valOpsObj返回。setIfAbsent(关键字,值);   }/* *   *为关键设置失效时间   * @param键键   * @param超时时间大小   * @param单位时间单位   */公共布尔到期(字符串键,长时间超时,TimeUnit unit) {   redisTemplate返回。到期(关键、超时、单元);   }/* *   *删除关键   * @param键键   */公共空间删除(String键){   redisTemplate.delete(关键);   }   }

完成了复述,访问工具类的实现,现在需要考虑的是如何去模拟竞争分布式锁。因为复述本身就是支持分布式集群的,所以只需要模拟出多线程处理业务场景。这里采用线程池来模拟,以下是测试类的具体实现:

@RestController   @RequestMapping (“test")   公开课TestController {      私有静态最终记录器日志=LoggerFactory.getLogger (TestController.class);//日志对象   @ autowired   私人RedisDao RedisDao;//定义的分布式锁键   私有静态最终字符串LOCK_KEY=癕yTestLock";      @RequestMapping(值=https://www.yisu.com/zixun/{“testRedisLock”},方法=RequestMethod.GET)   公共空间testRedisLock () {   ExecutorService ExecutorService=Executors.newFixedThreadPool (5);   for (int i=0;我<5;我+ +){   executorService。提交(新Runnable () {   @Override   公共空间run () {//获取分布式锁   布尔标志=redisDao。setIfObsent (LOCK_KEY,“锁”);   如果(国旗){   LOG.info (Thread.currentThread () . getname() +”:获取复述分布式锁成功”);//获取锁成功后设置失效时间   redisDao。到期(LOCK_KEY 2 TimeUnit.SECONDS);   尝试{   LOG.info (Thread.currentThread () . getname() +”:处理业务开始”);   thread . sleep (1000);//睡眠1000 ms模拟处理业务   LOG.info (Thread.currentThread () . getname() +”:处理业务结束”);//处理业务完成后删除锁   redisDao.delete (LOCK_KEY);   }捕捉(InterruptedException e) {   日志。错误(“处理业务异常:“,e);   }   其他}{   LOG.info (Thread.currentThread () . getname() +”:获取复述分布式锁失败”);   }   }   });   }   }   }

通过上面这段代码,可能会产生以下几个疑问:

线程如果获取分布式锁失败,为什么不尝试重新获取锁吗?

线程获取分布式锁成功后,设置了锁的失效时间,这个失效时间长短如何确定?

线程业务处理结束后,为什么要做删除锁的操作?

针对这几个疑问,我们可以来讨论下。

第一,复述的SETNX命令,如果关键已经存在,则不会做任何操作,所以SETNX实现的分布式锁并不是可重入锁。当然,也可以自己通过代码实现重试n次或者直至获取到分布式锁为止。但是,这不能保证竞争的公平性,某个线程会因为一直等待锁而阻塞。因此,复述,实现的分布式锁更适用于对共享资源一写多读的场景。

使用复述,实现分布式锁的方法