Redisson不光可以实现分布式锁,还可以实现分布式集合、分布式对象

253 阅读7分钟

Redisson 作为基于 Redis 的 Java 分布式框架,提供了丰富的分布式数据结构和服务,让开发者可以像操作本地 Java 对象一样处理分布式环境下的数据。下面详细讲解其核心组件:分布式锁   分布式集合   分布式对象 。

一、Redisson 分布式锁

分布式锁是 Redisson 最核心的功能之一,用于解决分布式系统中多节点并发竞争共享资源的问题。它基于 Redis 实现,同时弥补了原生 Redis 锁的缺陷(如不可重入、无自动续期等)。

1. 核心特性

  • 可重入性  :同一线程可多次获取同一把锁,避免死锁(类似 Java 的ReentrantLock)。
    -
     自动续期(WatchDog 机制) :若持有锁的线程未完成业务,会自动延长锁的过期时间(默认 30 秒续期一次),防止锁提前释放。
    -
     非阻塞获取  :支持tryLock()方法,可指定等待时间,避免无限阻塞。
    -
     公平锁 / 非公平锁  :公平锁按请求顺序分配锁,避免线程饥饿;非公平锁随机分配,性能更高。
    -
     红锁(RedLock)**:针对 Redis 集群,通过在多个独立节点获取锁,提升锁的可靠性(避免单节点故障导致锁失效)。

2. 常见锁类型及用法

Redisson 提供了多种锁实现,适配不同场景:

锁类型特点适用场景
RLock可重入锁(默认)大多数分布式并发场景(如投标、库存扣减)
RReadWriteLock读写锁(读共享、写互斥)读多写少场景(如商品详情查询与更新)
RFairLock公平锁(按请求顺序获取)对顺序性要求高的场景(如任务队列执行)
RedissonRedLock红锁(多节点锁)Redis 集群环境,需极高可靠性(如支付操作)

示例:可重入锁(RLock)

java

运行

@Service
public class BiddingService {
    @Autowired
    private RedissonClient redissonClient;

    public void submitBid(Long projectId, Long userId) {
        // 锁的key:同一用户对同一项目的投标互斥
        String lockKey = "bid:lock:" + projectId + ":" + userId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁:最多等5秒,获取后30秒自动过期(实际会被WatchDog续期)
            boolean locked = lock.tryLock(5, 30, TimeUnit.SECONDS);
            if (locked) {
                // 1. 验证资格(子步骤,可重入获取同一把锁)
                validateQualification(projectId, userId);
                // 2. 扣保证金
                deductDeposit(userId, projectId);
                // 3. 记录投标
                recordBid(projectId, userId);
            } else {
                throw new RuntimeException("获取锁失败,请重试");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 释放锁(仅当前线程持有锁时才释放)
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    // 子步骤:验证资格(可重入获取同一把锁)
    private void validateQualification(Long projectId, Long userId) {
        String lockKey = "bid:lock:" + projectId + ":" + userId;
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 同一线程再次获取锁,直接成功(重入性)
            lock.lock(); 
            // 业务逻辑:检查用户是否符合投标资格
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock(); // 重入次数-1
            }
        }
    }
}

3. 实现原理

Redisson 分布式锁基于 Redis 的SET命令(带NXPX参数)实现,核心逻辑:

  • 获取锁时,向 Redis 写入键值对(key=锁名称,value=UUID+线程ID),并设置过期时间。
  • 可重入性通过 “计数器” 实现:同一线程再次获取锁时,Redis 中存储的计数器 + 1。
  • WatchDog 机制:启动一个后台线程,每隔 10 秒(默认)检查锁是否仍被持有,若持有则延长过期时间。

二、Redisson 分布式集合

Redisson 提供了与 Java 集合 API 兼容的分布式集合,支持跨节点共享数据,同时保留集合的核心操作(如增删改查、交集、排序等)。

1. 核心特性

  • 分布式共享  :集合数据存储在 Redis 中,所有节点可访问(解决本地集合无法跨节点共享的问题)。
    -
     操作原子性  :集合的增删改查操作通过 Redis 的原子命令实现,避免并发修改导致的数据不一致。
    -
     丰富功能 **:支持过期时间、监听器(数据变化时触发回调)、批量操作等高级特性。

2. 常见分布式集合及用法

Redisson 的分布式集合几乎覆盖了 Java Collections Framework 的所有类型,核心包括:

集合类型对应 Redisson 类特点适用场景
映射(Map)RMap支持键过期、值序列化、监听器分布式缓存(如用户信息、商品数据)
列表(List)RList有序、可重复,支持索引操作分布式队列、任务列表
集合(Set)RSet无序、不可重复,支持交集 / 并集标签管理、去重场景(如用户已读消息 ID)
有序集(SortedSet)RSortedSet按分数排序,支持范围查询排行榜(如用户积分排名)
队列(Queue)RQueueFIFO(先进先出)分布式任务队列
双端队列(Deque)RDeque两端均可操作双向任务调度

示例 1:RMap(分布式 Map)

java

运行

@Service
public class UserCacheService {
    @Autowired
    private RedissonClient redissonClient;

    public void cacheUserInfo(Long userId, UserInfo userInfo) {
        // 获取分布式Map(键为用户ID,值为用户信息)
        RMap<Long, UserInfo> userMap = redissonClient.getMap("user:info");
        
        // 存储数据(支持过期时间:1小时后自动删除)
        userMap.put(userId, userInfo, 1, TimeUnit.HOURS);
        
        // 读取数据
        UserInfo cachedUser = userMap.get(userId);
        
        // 监听数据变化(当键被修改时触发)
        userMap.addListener((MapEntryListener<Long, UserInfo>) event -> {
            if (event.getEventType() == EntryEventType.UPDATE) {
                System.out.println("用户信息更新:" + event.getValue());
            }
        });
    }
}

示例 2:RSortedSet(分布式有序集合,排行榜场景)

java

运行

@Service
public class RankingService {
    @Autowired
    private RedissonClient redissonClient;

    // 新增用户积分
    public void addUserScore(Long userId, int score) {
        // 获取有序集合(按分数排序)
        RSortedSet<Long> scoreSet = redissonClient.getSortedSet("user:ranking");
        
        // 添加用户ID,分数作为排序依据
        scoreSet.add(score, userId);
    }

    // 获取Top10用户
    public List<Long> getTop10Users() {
        RSortedSet<Long> scoreSet = redissonClient.getSortedSet("user:ranking");
        // 按分数倒序取前10(从高到低)
        return new ArrayList<>(scoreSet.valueRange(-10, -1)); 
    }
}

三、Redisson 分布式对象

Redisson 提供了一系列分布式对象,用于在分布式环境中实现原子操作、对象共享等功能,弥补了 Java 原生对象无法跨节点共享的缺陷。

1. 核心特性

  • 跨节点共享  :对象数据存储在 Redis 中,所有节点可访问(如分布式计数器、分布式 ID 生成器)。
    -
     原子操作  :基于 Redis 的原子命令实现,避免并发修改导致的数据不一致。
    -
     序列化支持 **:支持 Java 对象的序列化 / 反序列化,可直接存储复杂对象。

2. 常见分布式对象及用法

Redisson 的分布式对象覆盖了原子类、二进制对象、信号量等,核心包括:

对象类型对应 Redisson 类特点适用场景
原子长整型RAtomicLong支持原子增减操作分布式计数器(如接口调用次数、订单编号)
二进制对象RBucket存储任意 Java 对象,支持过期分布式缓存(如会话数据、临时结果)
分布式 BitSetRBitSet位操作(如置位、清零、与 / 或)权限控制(如用户角色掩码)、布隆过滤器
信号量(Semaphore)RSemaphore控制并发访问数量限流(如同时最多 100 个请求访问接口)
可过期信号量RPermitExpirableSemaphore带过期时间的信号量临时资源占用(如限时抢购资格)

示例 1:RAtomicLong(分布式计数器)

java

运行

@Service
public class OrderCounterService {
    @Autowired
    private RedissonClient redissonClient;

    // 生成唯一订单号(原子自增)
    public Long generateOrderId() {
        // 获取分布式原子长整型
        RAtomicLong orderCounter = redissonClient.getAtomicLong("order:id:counter");
        
        // 原子自增并返回新值(确保分布式环境下唯一)
        return orderCounter.incrementAndGet();
    }
}

示例 2:RBucket(分布式对象存储)

java

运行

@Service
public class SessionService {
    @Autowired
    private RedissonClient redissonClient;

    // 存储用户会话(30分钟过期)
    public void saveSession(String sessionId, UserSession session) {
        // 获取二进制对象容器
        RBucket<UserSession> sessionBucket = redissonClient.getBucket("session:" + sessionId);
        
        // 存储对象,设置30分钟过期
        sessionBucket.set(session, 30, TimeUnit.MINUTES);
    }

    // 获取用户会话
    public UserSession getSession(String sessionId) {
        RBucket<UserSession> sessionBucket = redissonClient.getBucket("session:" + sessionId);
        return sessionBucket.get(); // 自动反序列化
    }
}

示例 3:RSemaphore(分布式信号量,限流场景)

java

运行

@Service
public class LimitService {
    @Autowired
    private RedissonClient redissonClient;

    // 初始化信号量:最多允许100个并发请求
    @PostConstruct
    public void initSemaphore() {
        RSemaphore semaphore = redissonClient.getSemaphore("api:limit");
        semaphore.trySetPermits(100); // 初始100个许可
    }

    // 接口访问前获取许可(限流)
    public boolean tryAccess() {
        RSemaphore semaphore = redissonClient.getSemaphore("api:limit");
        // 尝试获取1个许可,最多等1秒
        return semaphore.tryAcquire(1, 1, TimeUnit.SECONDS);
    }

    // 接口访问后释放许可
    public void releaseAccess() {
        RSemaphore semaphore = redissonClient.getSemaphore("api:limit");
        semaphore.release(); // 释放1个许可
    }
}

总结

Redisson 通过封装 Redis 的底层能力,提供了分布式锁分布式集合分布式对象三大核心组件,解决了分布式系统中的三大痛点:

  • 分布式锁:解决多节点并发竞争资源的问题;

  • 分布式集合:实现跨节点的数据共享与聚合操作;

  • 分布式对象:提供原子操作与跨节点对象存储。

这些组件的 API 设计与 Java 原生 API 高度兼容,大幅降低了分布式开发的复杂度,让开发者可以专注于业务逻辑,而非分布式细节。