本文转载自微信公众号“程序同事”,作者是楼下小黑哥。转载请联系项目总监公众号。重做总是比重建容易。最近在做一个项目,要把另一家公司的实现系统(以下简称老系统)完全集成到自己公司的系统(以下简称新系统)中,需要对方实现完整的功能也是在你自己的系统中实现。旧系统仍然有一些现有的商户。为了不影响现有商户的体验,新系统提供的对外接口必须与之前的保持一致。最后,系统完全切换后,功能只在新系统中运行,这就需要将旧系统中的数据完全迁移到新系统中。当然,这些都是在做这个项目之前就预料到的。本以为这个过程会很艰难,没想到这么艰难。本来觉得档期半年多,时间还是挺充裕的,现在感觉是个大坑,得一点一点的把坑填上。哎,说起来都是泪,我就不抱怨了,下次做完再给大家回顾一下我的真实经历。回到正文,在上一篇Redis分布式锁中,我们实现了基于Redis的分布式锁。这个分布式锁的基本功能没有问题,但是缺少可重入的特性,所以本文小黑就带大家实现一个可重入的分布式锁。本文将涵盖以下内容:ReentrantbasedonThreadLocalImplementationbasedonRedisHashImplementationreentrant说到可重入锁,首先我们来看看wiki上的一篇关于可重入的解释:“如果一个程序或者一个子程序可以”随时中断然后操作系统调度另一段代码去执行,而这段代码调用子程序没有错误”,所以称为可重入(reentrant或re-entrant)。即在子程序运行期间,执行线程可以重新进入进入并执行它仍然得到设计预期的结果。与多线程并发执行的线程安全不同,重入强调在单线程上执行时重新进入同一个子程序仍然是安全的。当一个线程执行一个块时代码并成功获取到锁,继续执行时,遇到被锁住的代码,重入保证线程可以继续执行,不可重入是指就是它需要等待锁被释放,可以再次成功获取到锁,然后可以继续执行。用一段Java代码来解释可重入:publicsynchronizedvoida(){b();}publicsynchronizedvoidb(){//pass}假设X线程在a方法获取锁b方法后继续执行,如果不是可重入这时,线程必须等待锁被释放,重新竞争锁。锁明明是X线程拥有的,但是还是需要等待自己释放锁,然后再去抢锁。这似乎很奇怪。我放飞自我~重入可以解决这个尴尬的问题。当线程拥有了锁之后,以后遇到加锁方法的时候,直接把加锁数加1,然后执行方法逻辑。退出加锁方法后,加锁数减1,当加锁数为0时,才真正释放锁。可以看出,可重入锁最大的特点就是计数,就是统计锁的数量。因此,在分布式环境中需要实现可重入锁时,我们还需要对锁的数量进行统计。分布式可重入锁的实现方式有两种:基于ThreadLocal的实现和基于RedisHash的实现。首先,让我们看一下基于ThreadLocal的实现。基于ThreadLocal实现的实现方法Java中的ThreadLocal允许每个线程都有自己的实例副本,我们可以利用这个特性来统计线程重入的次数。下面我们定义一个ThreadLocal全局变量LOCKS,内存存储Map实例变量。privatestaticThreadLocal