分布式锁通常有多种选择,例如基于Redis、基于Zookeeper、基于数据库等方案。Redis是用来缓存数据,在项目中使用的,所以更多的人使用Redis来做分布式锁。如果使用Redis作为锁,可以直接使用开源方案,比如redisson。最常见的用法如下:RLocklock=redisson.getLock("anyLock");lock.lock();run();lock.unlock();获取锁对象,调用lock()加锁,执行业务逻辑,调用unlock()释放锁。虽然框架提供的使用方法很简洁,但是我们还是需要对锁进行包裹。打包的目的是提高可扩展性和易用性。抽象接口如果我们直接使用redisson的原生API进行加锁,那么很多地方都会出现RLock相关的代码。突然有一天,由于某些原因,需要更换锁。这个时候变化的范围会比较大。凡是用到RLock的地方都要改。如下图所示:很多服务都使用了RLock.lock()方法。当我们需要更换锁时,所有涉及到的类和方法都要修改。修改的点显示在红色部分。所以我们需要做一个抽象层。我们可以定义一个DistributedLock接口来提供锁相关的能力,并提供多种实现,方便替换和扩展。如下图所示:每个Service都使用DistributedLock接口来加锁。当我们需要更换锁的实现时,不需要改变使用的地方,只需要更换DistributedLock的实现即可。自动释放自动释放是指加锁后需要在业务逻辑执行完毕后自动关闭锁。按照之前Redisson的方法,我们需要手动调用unlock()来释放持有的锁。当然Redisson也提供了超时释放的功能。一般情况下,业务执行完必须释放锁,才能继续处理下一次请求同一个锁。手动释放资源最常见的问题就是忘记释放,所以在JDK7中引入了try-with-resources来自动释放资源,相信大家都不陌生。所以在封装的时候,我们尽量不让用户手动发布,减少出错的概率。对于有结果的,我们可以使用Supplier来传递你的逻辑,对于没有返回结果的,我们可以使用Runnable来传递你的逻辑。/***Lock*@paramkeylockKey*@paramwaitTime尝试加锁,等待时间(ms)*@paramleaseTime加锁后无效时间(ms)*@paramsuccess加锁成功执行逻辑*@paramfail加锁失败执行逻辑*@return*/
