面试题答案
一键面试可能导致死锁的原因
- 锁的获取超时设置不合理:如果获取锁的等待时间设置过长,在高并发场景下,大量请求长时间等待获取锁,可能导致线程长时间阻塞,资源无法释放,进而引发死锁。例如,一个线程持有锁进行复杂业务处理,其他线程无限期等待获取该锁。
- 锁的释放异常:在业务执行过程中,如果发生异常,导致锁没有被正确释放,那么后续其他线程永远无法获取到该锁,造成死锁。比如,代码在执行数据库操作时抛出异常,而释放锁的代码没有被执行。
- 多锁依赖顺序不一致:当一个业务场景需要获取多个锁时,如果不同线程获取锁的顺序不一致,就可能形成死循环等待,导致死锁。例如,线程A先获取锁1再获取锁2,而线程B先获取锁2再获取锁1,此时就可能产生死锁。
通过合理设置Redis锁机制防止死锁的方法
- 设置合理的锁获取超时时间:在使用Redis获取锁时,设置一个合适的超时时间,避免线程长时间等待。例如,在Java中使用Jedis获取锁时,可以通过
setnx
命令结合expire
命令,设置一个合理的过期时间,如:
Jedis jedis = new Jedis("localhost");
String lockKey = "myLock";
String requestId = UUID.randomUUID().toString();
if ("OK".equals(jedis.set(lockKey, requestId, "NX", "EX", 10))) {
// 获取锁成功,执行业务逻辑
try {
// 业务代码
} finally {
// 释放锁
if (requestId.equals(jedis.get(lockKey))) {
jedis.del(lockKey);
}
}
} else {
// 获取锁失败
}
这里设置锁的过期时间为10秒,如果10秒内没有获取到锁,就放弃等待,避免长时间阻塞。
2. 确保锁的正确释放:使用try - finally
语句块,在获取锁成功后,无论业务逻辑是否出现异常,都保证锁能够被正确释放。如上述Java代码示例,在finally
块中判断当前线程持有的锁标识与Redis中存储的是否一致,一致则释放锁。
3. 统一多锁获取顺序:在涉及多个锁的场景下,制定统一的锁获取顺序。例如,对于需要获取锁1和锁2的业务,所有线程都按照先获取锁1再获取锁2的顺序进行操作,避免因获取顺序不一致导致死锁。