redis有一个命令是setIfAbsent,只要redis里存在了这个值还会false,或者还会true。
每个线程进来时,都先判断是否有(Boolean result = strRedisTrmplate.opsForValue().setIfAbsent("键","值") ),如果为true(数据库之前不存在这个值),就设置进去,执行业务代码,最后删除这个值(strRedisTrmplate。delete("键"))
业务代码进行try, 删除操作必须放在filnally里面。避免业务代码错误,不然所有线程过来都会拿到false。
但是如果系统突然宕机了,删除操作还是没有执行到,也会出现问题。这个时候就必须给setIfAbsent 设置过期时间, strRedisTrmplate.opsForValue().setIfAbsent("键","值",10,TimeUnit.SECINDS),如果业务代码执行超过10秒,那其他线程进来可能就这个加锁就会失效(比如第一个线程执行15秒,10秒的时候加锁失效,第二个线程进来又加锁成功,5秒后第一个线程把第二个的删除了,第三个线程又进来,如此循环会造成线程会删除不是自己线程的锁,这个时候为了避免删除其他线程的锁,会把值改成线程的唯一id,只有线程id才能删除自己的锁)。但是还是怕这个时间设置得不够(业务执行时间太长),这个时候会增加一个定时器,查看当前线程是否在执行,如果还在执行,就给redis增加时间(续命)。这个就有一个插件(redisson)他就实现这些操作。
但是为了更好保证完全没有问题的话,最后使用zookeeper分布锁。