1. setnx,拿到就执行,拿不到不执行,finally块中添加释放锁。

    问题:实例非正常关闭,锁无法正常释放。

  2. setnx, 添加锁过期时间,

    问题:此线程在锁过期时间内未执行完操作,导致其他线程入锁,此线程释放其他线程锁

  3. 为锁添加标识,每个线程只能释放自己的锁

    问题:检测锁、释放锁非原子操作

  4. 引入lua脚本,保证释放锁的原子性

    问题:若此线程过期时间未执行完操作,其他线程入锁,两个线程可能出现同时修改共享数据的操作。

    // 本人IM项目部分代码,编码环境:JDK17
    public GroupInfo selectGroupInfo(long groupKey) {
            String key = String.valueOf(groupKey);
            // 从redis中获取缓存
            String cacheObject = redisTemplate.opsForValue().get(key);
            // 判断缓存有效
            if (cacheObject != null && !cacheObject.isEmpty()) {
                return JSON.parseObject(cacheObject, GroupInfo.class);
            }
            Boolean lock = null;
            String uuid = null;
            // 添加分布式锁防止mysql压力过大
            try {
                // 锁标识
                uuid = UUID.randomUUID().toString();
                // 每个群有一把锁,过期时间为10s
                lock = redisTemplate.opsForValue().setIfAbsent(key+"LOCK", uuid, 10, TimeUnit.SECONDS);
                if (Boolean.TRUE.equals(lock)) {
                    // 拿到锁
                    GroupInfo groupInfo = groupDao.selectGroupInfo(groupKey);
                    // 缓存
                    redisTemplate.opsForValue().set(key, JSON.toJSONString(groupInfo));
                    // 设置过期时间
                    redisTemplate.expire(key, 1, TimeUnit.DAYS);
                    // 返回值
                    return groupInfo;
                } else {
                    // 没拿到锁
                    throw new RuntimeException();
                }
            } finally {
                if (Boolean.TRUE.equals(lock)) {
                    // 如果有拿到锁就释放锁
                    String script = " if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end ";
                    DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
                    redisScript.setScriptSource(new StaticScriptSource(script));
                    redisTemplate.execute(redisScript, Collections.singletonList(key+"LOCK"), uuid);
                }
            }
        }
  5. 锁续约,Redisson 看门狗机制

    问题:redis集群中,锁还未同步,master节点宕机,slave节点拿不到锁

  6. redisson红锁,所有redis节点都拿到锁才算成功加锁

    问题:延迟问题

  7. 分段锁|可重入锁|公平锁|非公平锁|联锁|红锁|读写锁|信号锁|可过期信号量|分布式闭锁|间隙锁

    1. 分段锁(Segment Locking):将数据分成多个段或区段,并对每个段应用锁,以提高并发性能。

    2. 可重入锁(Reentrant Lock):允许线程在持有锁的情况下多次进入同步代码块,提高代码的灵活性和简洁性。

    3. 公平锁(Fair Lock):按照申请锁的顺序依次获取锁,避免线程饥饿现象。

    4. 非公平锁(Non-Fair Lock):允许线程在没有按照申请锁的顺序的情况下获取锁,可能导致线程饥饿现象。

    5. 联锁(Deadlock):预防死锁,成功拿到所有资源才算成功加锁,否则释放资源。

    6. 红锁(Redlock):一种分布式锁算法,通过在多个 Redis 实例上获取锁来实现分布式锁的目的,具有较高的可用性和可靠性。

    7. 读写锁(Read-Write Lock):允许多个线程同时读取共享数据,但只允许一个线程写入共享数据,以提高读取性能。

    8. 信号锁(Semaphore):限制同时访问某一资源的线程数量,允许多个线程同时访问资源,但要求总访问量不超过指定数量。

    9. 分布式闭锁(Distributed CountDownLatch):一种分布式同步工具,用于阻塞多个线程直到某个条件满足,可以用于实现分布式任务的协调和同步。

    10. 间隙锁(Gap Lock)是一种数据库锁机制,用于锁定数据范围而不是具体的数据行。当事务使用范围查询或批量操作时,间隙锁可以确保其他事务无法在查询范围内插入新数据或修改现有数据,从而保证数据的一致性和隔离性。