Redis分布式锁常见坑点分析( 二 )


三、线程加锁成功后继续申请加锁

?这个场景主要发生在加锁代码内部调用栈过深,比如说加锁成功执行方法 a,在方法 a 内又重复申请了同一把锁 , 导致线程把自己锁住了,这个业界的主流叫法是叫锁的可重入性 。
?
解决方式有两种,一是修改方法内的加锁逻辑,不要加同一把锁 , 修改方法 a 内的加锁 key 名称 。二是针对加锁逻辑做修改,实现可重入性 。
这里简单介绍如何实现可重入性,给每个线程设置请求ID , 加锁成功将请求ID设置为加锁 key 的对应 value,针对同一个线程的重复加锁,判断当前线程已存在请求ID的情况下,请求ID直接与加锁 key 的对应 value 相比较,相同则直接返回加锁成功 。
四、 代码实践4.1 加锁自动续期实践设置锁过期时间为10秒 , 然后该任务执行15秒,代码如下:
?ps: 以下代码都可以在 https://github.com/wayn111/newbee-mall-pro 项目 test 目录下 RedisLockTest 类中找到
?
@Slf4j@SpringBootTest@RunWith(SpringRunner.class)public class RedisLockTest {    @Autowired    private RedisLock redisLock;    @Test    @Test    public void redisLockNeNewTest() {        String key = "test";        try {            log.info("---申请加锁");            if (redisLock.lock(key, 10)) {                // 模拟任务执行15秒                log.info("---加锁成功");                Thread.sleep(15000);                log.info("---执行完毕");            }        } catch (Exception e) {            log.error(e.getMessage(), e);        } finally {            redisLock.unLock(key);        }    }}执行如下:

Redis分布式锁常见坑点分析

文章插图
可以看出就算任务执行超过过期时间也能通过自动续期让代码正常执行 。
4.2 多线程下其他线程无法共同申请到同一把锁实践启动两个线程,线程 A 先加锁 ,  线程 B 后枷锁
@Testpublic void redisLockReleaseSelfTest() throws IOException {    new Thread(() -> {        String key = "test";        try {            log.info("---申请加锁");            if (redisLock.lock(key, 10)) {                // 模拟任务执行15秒                log.info("---加锁成功");                Thread.sleep(15000);                log.info("---执行完毕");            } else {                log.info("---加锁失败");            }        } catch (Exception e) {            log.error(e.getMessage(), e);        } finally {            redisLock.unLock(key);        }    }, "thread-A").start();    new Thread(() -> {        String key = "test";        try {            Thread.sleep(100L);            log.info("---申请加锁");            if (redisLock.lock(key, 10)) {                // 模拟任务执行15秒                log.info("---加锁成功");                Thread.sleep(15000);                log.info("---执行完毕");            } else {                log.info("---加锁失败");            }        } catch (Exception e) {            log.error(e.getMessage(), e);        } finally {            redisLock.unLock(key);        }    }, "thread-B").start();    System.in.read();}


推荐阅读