Redisson:分布式系统的Java神器 🚀
Redisson是一个功能强大、设计优雅的Redis Java客户端,它不仅仅是一个简单的Redis连接器,更是一个完整的分布式解决方案!想象一下,如果你正在构建一个高并发的电商平台,需要处理大量用户的秒杀请求,或者需要在多个服务实例之间共享会话状态,Redisson就是你的得力助手。
Redisson的核心特点:
- 🎯 丰富的分布式对象:提供分布式锁、集合、计数器等Java常用对象
- ⚡ 高性能:基于Netty实现,性能卓越
- 🔒 分布式锁:支持可重入锁、公平锁、联锁等多种锁类型
- 📊 分布式集合:提供Map、Set、List、Queue等分布式集合类型
- 🎪 高级功能:支持布隆过滤器、延迟队列、分布式服务等
- 🌐 多Redis模式:支持单机、主从、哨兵、集群等多种Redis部署模式
Redisson让分布式系统的开发变得简单而有趣,让你的代码在分布式环境中也能像单机应用一样优雅地运行。
高级功能实战
1. 分布式锁
java
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
/**
* 分布式锁生产级使用示例
*/
public class DistributedLockExample {
private final RedissonClient redissonClient;
public DistributedLockExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 带超时控制的分布式锁
*
* @param lockKey 锁的key
* @param leaseTime 自动释放时间
* @param unit 时间单位
* @param task 需要执行的任务
* @return 任务执行结果
*/
public boolean executeWithLock(String lockKey, long leaseTime, TimeUnit unit, Runnable task) {
RLock lock = redissonClient.getLock(lockKey);
try {
// 尝试获取锁,最多等待10秒,锁自动释放时间为leaseTime
boolean acquired = lock.tryLock(10, leaseTime, unit);
if (acquired) {
try {
// 执行业务逻辑
task.run();
return true;
} finally {
// 确保锁被释放,防止死锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} else {
System.out.println("获取锁失败,锁已被其他线程持有: " + lockKey);
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("获取锁过程中被中断: " + e.getMessage());
// 恢复中断状态
return false;
}
}
/**
* 看门狗模式锁 - 自动续期
*
* @param lockKey 锁的key
* @param task 需要执行的任务
*/
public boolean executeWithWatchdogLock(String lockKey, Runnable task) {
RLock lock = redissonClient.getLock(lockKey);
try {
// 使用看门狗模式,Redisson会自动续期
lock.lock(30, TimeUnit.SECONDS);
try {
task.run();
return true;
} finally {
// 确保锁被释放
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} catch (Exception e) {
System.err.println("执行带锁任务时发生异常: " + e.getMessage());
return false;
}
}
}
2. 分布式集合
java
import org.redisson.api.RList;
import org.redisson.api.RMap;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import java.util.Collection;
import java.util.Map;
/**
* 分布式集合生产级使用示例
*/
public class DistributedCollectionsExample {
private final RedissonClient redissonClient;
public DistributedCollectionsExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 分布式列表操作
*
* @param listName 列表名称
* @param items 要添加的项目
* @return 操作结果
*/
public boolean operateList(String listName, Collection<String> items) {
try {
RList<String> list = redissonClient.getList(listName);
// 添加多个元素
list.addAll(items);
// 获取列表大小
int size = list.size();
System.out.println("列表 " + listName + " 的大小: " + size);
// 获取指定范围的元素
if (size > 0) {
int endIndex = Math.min(10, size); // 最多取10个元素
java.util.List<String> subList = list.subList(0, endIndex);
System.out.println("列表前" + endIndex + "个元素: " + subList);
}
return true;
} catch (Exception e) {
System.err.println("操作列表时发生异常: " + e.getMessage());
return false;
}
}
/**
* 分布式Map操作
*
* @param mapName Map名称
* @param data 要存储的数据
* @return 操作结果
*/
public boolean operateMap(String mapName, Map<String, Object> data) {
try {
RMap<String, Object> map = redissonClient.getMap(mapName);
// 批量添加数据
map.putAll(data);
// 原子性操作示例:仅当key不存在时才添加
map.putIfAbsent("newKey", "newValue");
// 获取所有键值对
System.out.println("Map " + mapName + " 的所有键值对: " + map.readAllMap());
// 获取Map大小
int size = map.size();
System.out.println("Map " + mapName + " 的大小: " + size);
// 安全删除键值对
Object removedValue = map.remove("tempKey");
System.out.println("删除的键值对: " + removedValue);
return true;
} catch (Exception e) {
System.err.println("操作Map时发生异常: " + e.getMessage());
return false;
}
}
/**
* 分布式Set操作
*
* @param setName Set名称
* @param elements 要添加的元素
* @return 操作结果
*/
public boolean operateSet(String setName, Collection<String> elements) {
try {
RSet<String> set = redissonClient.getSet(setName);
// 添加元素并返回是否成功添加(true表示元素不存在,false表示已存在)
for (String element : elements) {
boolean added = set.add(element);
if (!added) {
System.out.println("元素已存在: " + element);
}
}
// 检查元素是否存在
boolean contains = set.contains("checkElement");
System.out.println("Set " + setName + " 包含 'checkElement': " + contains);
// 获取Set大小
int size = set.size();
System.out.println("Set " + setName + " 的大小: " + size);
// 获取所有元素
java.util.Set<String> allElements = set.readAll();
System.out.println("Set " + setName + " 的所有元素: " + allElements);
return true;
} catch (Exception e) {
System.err.println("操作Set时发生异常: " + e.getMessage());
return false;
}
}
}
3. 分布式计数器
java
import org.redisson.api.RAtomicLong;
import org.redisson.api.RCountDownLatch;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
/**
* 分布式计数器生产级使用示例
*/
public class DistributedCountersExample {
private final RedissonClient redissonClient;
public DistributedCountersExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 原子长整型计数器操作
*
* @param counterName 计数器名称
* @return 当前计数值
*/
public long operateAtomicCounter(String counterName) {
try {
RAtomicLong atomicLong = redissonClient.getAtomicLong(counterName);
// 原子递增并返回新值
long newValue = atomicLong.incrementAndGet();
System.out.println("计数器 " + counterName + " 递增后值: " + newValue);
// 原子递减并返回新值
long decrementedValue = atomicLong.decrementAndGet();
System.out.println("计数器 " + counterName + " 递减后值: " + decrementedValue);
// 获取当前值
long currentValue = atomicLong.get();
System.out.println("计数器 " + counterName + " 当前值: " + currentValue);
// 条件更新 - CAS操作
boolean updated = atomicLong.compareAndSet(currentValue, currentValue + 10);
if (updated) {
System.out.println("计数器 " + counterName + " CAS更新成功");
} else {
System.out.println("计数器 " + counterName + " CAS更新失败");
}
return atomicLong.get();
} catch (Exception e) {
System.err.println("操作原子计数器时发生异常: " + e.getMessage());
return -1;
}
}
/**
* 分布式CountDownLatch操作
*
* @param latchName 倒计时器名称
* @param count 初始计数
* @param task 待执行的任务
*/
public void operateCountDownLatch(String latchName, int count, Runnable task) {
try {
RCountDownLatch latch = redissonClient.getCountDownLatch(latchName);
// 设置初始计数(仅在计数为0时有效)
if (latch.getCount() == 0) {
latch.trySetCount(count);
}
System.out.println("倒计时器 " + latchName + " 初始计数: " + latch.getCount());
// 启动一个线程执行任务并倒计时
new Thread(() -> {
try {
task.run();
// 任务完成,倒计时
latch.countDown();
System.out.println("任务完成,倒计时器 " + latchName + " 减1");
} catch (Exception e) {
System.err.println("执行任务时发生异常: " + e.getMessage());
}
}).start();
// 等待所有任务完成(带超时)
boolean completed = latch.await(30, TimeUnit.SECONDS);
if (completed) {
System.out.println("所有任务已完成");
} else {
System.out.println("等待超时,任务可能未完成");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("等待倒计时器时被中断: " + e.getMessage());
} catch (Exception e) {
System.err.println("操作倒计时器时发生异常: " + e.getMessage());
}
}
}
4. 信号量 (Semaphore)
java
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
/**
* 信号量生产级使用示例
*/
public class SemaphoreExample {
private final RedissonClient redissonClient;
public SemaphoreExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 信号量资源访问控制
*
* @param semaphoreName 信号量名称
* @param permits 初始许可证数量
* @param task 需要限制并发的任务
* @return 操作结果
*/
public boolean controlAccessWithSemaphore(String semaphoreName, int permits, Runnable task) {
try {
RSemaphore semaphore = redissonClient.getSemaphore(semaphoreName);
// 初始化许可证数量(仅在许可证为0时设置)
semaphore.trySetPermits(permits);
// 获取许可证(带超时)
boolean acquired = semaphore.tryAcquire(5, TimeUnit.SECONDS);
if (acquired) {
try {
System.out.println("获取到许可证,开始执行任务");
task.run();
return true;
} finally {
// 释放许可证
semaphore.release();
System.out.println("任务完成,释放许可证");
}
} else {
System.out.println("获取许可证超时,资源访问受限");
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("获取许可证时被中断: " + e.getMessage());
return false;
} catch (Exception e) {
System.err.println("使用信号量时发生异常: " + e.getMessage());
return false;
}
}
/**
* 批量获取和释放许可证
*
* @param semaphoreName 信号量名称
* @param permitsToAcquire 要获取的许可证数量
* @param permitsToRelease 要释放的许可证数量
* @return 操作结果
*/
public boolean batchOperateSemaphore(String semaphoreName, int permitsToAcquire, int permitsToRelease) {
try {
RSemaphore semaphore = redissonClient.getSemaphore(semaphoreName);
// 批量获取许可证
boolean acquired = semaphore.tryAcquire(permitsToAcquire, 10, TimeUnit.SECONDS);
if (acquired) {
try {
System.out.println("批量获取 " + permitsToAcquire + " 个许可证成功");
// 执行需要多许可证的任务
return true;
} finally {
// 批量释放许可证
semaphore.release(permitsToRelease);
System.out.println("批量释放 " + permitsToRelease + " 个许可证");
}
} else {
System.out.println("批量获取 " + permitsToAcquire + " 个许可证失败");
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("批量获取许可证时被中断: " + e.getMessage());
return false;
} catch (Exception e) {
System.err.println("批量操作信号量时发生异常: " + e.getMessage());
return false;
}
}
}
5. 分布式队列
java
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RQueue;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
/**
* 分布式队列生产级使用示例
*/
public class DistributedQueueExample {
private final RedissonClient redissonClient;
public DistributedQueueExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 普通队列操作
*
* @param queueName 队列名称
* @param items 要添加的项目
* @return 操作结果
*/
public boolean operateQueue(String queueName, java.util.List<String> items) {
try {
RQueue<String> queue = redissonClient.getQueue(queueName);
// 添加多个元素到队列
for (String item : items) {
boolean added = queue.offer(item);
if (!added) {
System.out.println("队列已满,无法添加元素: " + item);
}
}
// 获取队列大小
int size = queue.size();
System.out.println("队列 " + queueName + " 当前大小: " + size);
// 非阻塞获取元素
String element = queue.poll(); // 获取并移除队首元素,如果队列为空返回null
if (element != null) {
System.out.println("从队列获取元素: " + element);
} else {
System.out.println("队列为空");
}
return true;
} catch (Exception e) {
System.err.println("操作队列时发生异常: " + e.getMessage());
return false;
}
}
}
6. 延迟队列 (Delayed Queue)
java
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
/**
* 延迟队列生产级使用示例
*/
public class DelayedQueueExample {
private final RedissonClient redissonClient;
public DelayedQueueExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 延迟队列操作
*
* @param queueName 队列名称
* @param delayedItems 延迟项目列表,包含项目和延迟时间
*/
public void operateDelayedQueue(String queueName, java.util.List<DelayedItem> delayedItems) {
RBlockingQueue<String> queue = redissonClient.getBlockingQueue(queueName);
RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(queue);
try {
// 添加延迟元素
for (DelayedItem item : delayedItems) {
delayedQueue.offer(item.item, item.delay, item.unit);
System.out.println("添加延迟元素: " + item.item +
",延迟时间: " + item.delay + " " + item.unit);
}
// 启动消费者线程处理延迟元素
Thread consumerThread = new Thread(() -> {
try {
while (!Thread.currentThread().isInterrupted()) {
// 阻塞等待延迟时间到达的元素
String item = queue.take();
System.out.println("获取到延迟元素: " + item +
",到达时间: " + System.currentTimeMillis());
// 处理延迟元素
processDelayedItem(item);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("消费者线程被中断");
} catch (Exception e) {
System.err.println("处理延迟元素时发生异常: " + e.getMessage());
}
});
consumerThread.start();
// 等待一段时间观察结果
Thread.sleep(10000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("主线程被中断: " + e.getMessage());
} catch (Exception e) {
System.err.println("操作延迟队列时发生异常: " + e.getMessage());
} finally {
// 重要:使用完延迟队列后必须销毁
delayedQueue.destroy();
}
}
/**
* 处理延迟元素的业务逻辑
*
* @param item 延迟元素
*/
private void processDelayedItem(String item) {
System.out.println("处理延迟元素: " + item);
// 实际业务处理逻辑
}
/**
* 延迟元素封装类
*/
public static class DelayedItem {
public final String item;
public final long delay;
public final TimeUnit unit;
public DelayedItem(String item, long delay, TimeUnit unit) {
this.item = item;
this.delay = delay;
this.unit = unit;
}
}
}
7. 发布/订阅模式
java
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 发布/订阅模式生产级使用示例
*/
public class PubSubExample {
private final RedissonClient redissonClient;
private final ExecutorService executorService;
public PubSubExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
this.executorService = Executors.newCachedThreadPool();
}
/**
* 订阅消息并处理
*
* @param topicName 主题名称
* @param messageHandler 消息处理器
*/
public void subscribeTopic(String topicName, java.util.function.Consumer<String> messageHandler) {
RTopic topic = redissonClient.getTopic(topicName);
// 添加消息监听器
int listenerId = topic.addListener(String.class, new MessageListener<String>() {
@Override
public void onMessage(CharSequence channel, String msg) {
System.out.println("收到消息 - 频道: " + channel + ",内容: " + msg);
// 在独立线程中处理消息,避免阻塞Redisson的消息处理线程
executorService.submit(() -> {
try {
messageHandler.accept(msg);
} catch (Exception e) {
System.err.println("处理消息时发生异常: " + e.getMessage());
}
});
}
});
System.out.println("已订阅主题: " + topicName + ",监听器ID: " + listenerId);
}
/**
* 发布消息
*
* @param topicName 主题名称
* @param message 消息内容
* @return 发布的消息数量
*/
public long publishMessage(String topicName, String message) {
try {
RTopic topic = redissonClient.getTopic(topicName);
// 发布消息
long receivers = topic.publish(message);
System.out.println("消息已发布到主题: " + topicName +
",接收者数量: " + receivers +
",消息内容: " + message);
return receivers;
} catch (Exception e) {
System.err.println("发布消息时发生异常: " + e.getMessage());
return 0;
}
}
/**
* 异步发布消息
*
* @param topicName 主题名称
* @param message 消息内容
* @return CompletableFuture表示发布结果
*/
public CompletableFuture<Long> publishMessageAsync(String topicName, String message) {
try {
RTopic topic = redissonClient.getTopic(topicName);
// 异步发布消息
return topic.publishAsync(message)
.toCompletableFuture()
.whenComplete((result, throwable) -> {
if (throwable != null) {
System.err.println("异步发布消息失败: " + throwable.getMessage());
} else {
System.out.println("异步发布消息成功,接收者数量: " + result);
}
});
} catch (Exception e) {
System.err.println("异步发布消息时发生异常: " + e.getMessage());
return CompletableFuture.completedFuture(0L);
}
}
/**
* 关闭资源
*/
public void shutdown() {
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdown();
}
}
}
8. 布隆过滤器 (Bloom Filter)
java
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import java.util.Collection;
/**
* 布隆过滤器生产级使用示例
*/
public class BloomFilterExample {
private final RedissonClient redissonClient;
public BloomFilterExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 创建并初始化布隆过滤器
*
* @param filterName 过滤器名称
* @param expectedInsertions 预期插入元素数量
* @param falseProbability 误判率
* @return 布隆过滤器实例
*/
public RBloomFilter<String> createBloomFilter(String filterName,
long expectedInsertions,
double falseProbability) {
try {
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(filterName);
// 初始化布隆过滤器(仅在未初始化时设置)
if (!bloomFilter.isExists()) {
boolean initialized = bloomFilter.tryInit(expectedInsertions, falseProbability);
if (initialized) {
System.out.println("布隆过滤器 " + filterName +
" 初始化成功,预期插入数量: " + expectedInsertions +
",误判率: " + falseProbability);
} else {
System.out.println("布隆过滤器 " + filterName + " 已存在,跳过初始化");
}
} else {
System.out.println("布隆过滤器 " + filterName + " 已存在");
}
return bloomFilter;
} catch (Exception e) {
System.err.println("创建布隆过滤器时发生异常: " + e.getMessage());
throw new RuntimeException("创建布隆过滤器失败", e);
}
}
/**
* 批量添加元素到布隆过滤器
*
* @param filterName 过滤器名称
* @param elements 要添加的元素集合
* @return 成功添加的元素数量
*/
public int batchAddElements(String filterName, Collection<String> elements) {
try {
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(filterName);
if (!bloomFilter.isExists()) {
System.out.println("布隆过滤器 " + filterName + " 不存在,无法添加元素");
return 0;
}
int addedCount = 0;
for (String element : elements) {
boolean added = bloomFilter.add(element);
if (added) {
addedCount++;
}
}
System.out.println("批量添加元素完成,成功添加: " + addedCount + " 个元素");
return addedCount;
} catch (Exception e) {
System.err.println("批量添加元素到布隆过滤器时发生异常: " + e.getMessage());
return 0;
}
}
/**
* 检查元素是否可能存在于布隆过滤器中
*
* @param filterName 过滤器名称
* @param element 要检查的元素
* @return true表示可能存在,false表示一定不存在
*/
public boolean mightContain(String filterName, String element) {
try {
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(filterName);
if (!bloomFilter.isExists()) {
System.out.println("布隆过滤器 " + filterName + " 不存在");
return false;
}
boolean mightContain = bloomFilter.contains(element);
System.out.println("元素 '" + element + "' 在过滤器 " + filterName +
" 中可能存在: " + mightContain);
return mightContain;
} catch (Exception e) {
System.err.println("检查布隆过滤器时发生异常: " + e.getMessage());
return false;
}
}
/**
* 使用布隆过滤器防止缓存穿透的完整示例
*
* @param userId 用户ID
* @return 用户信息(如果存在)
*/
public String preventCachePenetration(String userId) {
String filterName = "user_exists_filter";
String cacheKey = "user_cache:" + userId;
// 创建布隆过滤器
RBloomFilter<String> bloomFilter = createBloomFilter(filterName, 1000000, 0.03);
// 首先检查布隆过滤器
if (!bloomFilter.contains(userId)) {
// 布隆过滤器确认元素不存在,直接返回,避免查询缓存和数据库
System.out.println("布隆过滤器确认用户不存在: " + userId);
return null;
}
// 布隆过滤器认为可能存在,继续查询缓存
// 这里应该查询实际缓存,但为了示例,我们模拟
System.out.println("布隆过滤器认为用户可能存在,继续查询缓存/数据库: " + userId);
// 模拟查询缓存和数据库的逻辑
String userInfo = queryUserInfo(userId);
if (userInfo == null) {
// 如果数据库中确实不存在,可以考虑将该ID加入布隆过滤器
// 但需要谨慎处理,因为用户可能在稍后创建
System.out.println("用户在数据库中不存在: " + userId);
} else {
// 如果用户存在,将信息存储到缓存
System.out.println("用户存在,更新缓存: " + userId);
}
return userInfo;
}
/**
* 模拟查询用户信息
*/
private String queryUserInfo(String userId) {
// 实际应用中这里会查询缓存或数据库
// 为了示例,我们模拟一个简单的逻辑
if ("valid_user".equals(userId)) {
return "用户信息: " + userId;
}
return null;
}
}
6. 分布式对象
java
import org.redisson.api.RBucket;
import org.redisson.api.RSet;
public class DistributedObjectsExample {
// 自定义对象
static class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// getter和setter方法
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
public void objectsExample(RedissonClient redisson) {
// 存储单个对象
RBucket<Person> bucket = redisson.getBucket("person");
bucket.set(new Person("张三", 30));
Person person = bucket.get(); // 获取对象
System.out.println(person.getName()); // 输出: 张三
// 存储对象集合
RSet<Person> personSet = redisson.getSet("personSet");
personSet.add(new Person("李四", 25));
personSet.add(new Person("王五", 35));
}
}
实际应用场景
1. 分布式锁 - 防止重复操作
java
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CompletableFuture;
/**
* 分布式锁生产级应用场景示例
*/
public class DistributedLockScenario {
private final RedissonClient redissonClient;
private static final long DEFAULT_LEASE_TIME = 30; // 默认租约时间30秒
private static final long DEFAULT_WAIT_TIME = 10; // 默认等待时间10秒
public DistributedLockScenario(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 安全的分布式锁操作
*
* @param lockKey 锁的key
* @param businessLogic 业务逻辑
* @return 操作结果
*/
public boolean executeWithDistributedLock(String lockKey, Runnable businessLogic) {
RLock lock = null;
try {
lock = redissonClient.getLock(lockKey);
// 尝试获取锁,最多等待DEFAULT_WAIT_TIME秒,锁自动释放时间为DEFAULT_LEASE_TIME秒
boolean acquired = lock.tryLock(DEFAULT_WAIT_TIME, DEFAULT_LEASE_TIME, TimeUnit.SECONDS);
if (acquired) {
try {
System.out.println("获取到分布式锁: " + lockKey +
",线程: " + Thread.currentThread().getName());
// 执行业务逻辑
businessLogic.run();
return true;
} finally {
// 确保锁被释放,防止死锁
if (lock != null && lock.isHeldByCurrentThread()) {
lock.unlock();
System.out.println("释放分布式锁: " + lockKey);
}
}
} else {
System.out.println("获取分布式锁失败,锁已被其他线程持有: " + lockKey);
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("获取分布式锁过程中被中断: " + e.getMessage());
// 恢复中断状态并尝试释放锁
if (lock != null && lock.isHeldByCurrentThread()) {
try {
lock.unlock();
} catch (Exception unlockException) {
System.err.println("释放锁时发生异常: " + unlockException.getMessage());
}
}
return false;
} catch (Exception e) {
System.err.println("执行带锁操作时发生异常: " + e.getMessage());
return false;
}
}
/**
* 异步执行带锁操作
*
* @param lockKey 锁的key
* @param businessLogic 业务逻辑
* @return CompletableFuture表示操作结果
*/
public CompletableFuture<Boolean> executeWithDistributedLockAsync(String lockKey, Runnable businessLogic) {
return CompletableFuture.supplyAsync(() -> {
return executeWithDistributedLock(lockKey, businessLogic);
});
}
/**
* 订单处理场景 - 防止重复下单
*
* @param userId 用户ID
* @param orderId 订单ID
* @return 处理结果
*/
public boolean processOrder(String userId, String orderId) {
// 使用用户ID和订单ID作为锁的key,防止同一用户重复下单
String lockKey = "order_lock:" + userId + ":" + orderId;
return executeWithDistributedLock(lockKey, () -> {
// 检查订单是否已存在
if (isOrderExists(orderId)) {
System.out.println("订单已存在,跳过处理: " + orderId);
return;
}
// 执行订单创建逻辑
System.out.println("开始处理订单: " + orderId + ",用户: " + userId);
// 模拟订单处理时间
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 保存订单
saveOrder(orderId, userId);
System.out.println("订单处理完成: " + orderId);
});
}
/**
* 模拟检查订单是否存在
*/
private boolean isOrderExists(String orderId) {
// 实际应用中这里会查询数据库或缓存
return false;
}
/**
* 模拟保存订单
*/
private void saveOrder(String orderId, String userId) {
// 实际应用中这里会保存到数据库
System.out.println("订单已保存 - 订单ID: " + orderId + ",用户ID: " + userId);
}
}
2. 信号量 - 限制并发访问
java
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* 信号量生产级应用场景示例
*/
public class SemaphoreScenario {
private final RedissonClient redissonClient;
private static final String RESOURCE_ACCESS_PREFIX = "resource_access:";
public SemaphoreScenario(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 资源访问控制
*
* @param resourceId 资源ID
* @param maxConcurrent 最大并发数
* @param accessTask 访问任务
* @return 访问结果
*/
public boolean controlResourceAccess(String resourceId, int maxConcurrent, Runnable accessTask) {
String semaphoreKey = RESOURCE_ACCESS_PREFIX + resourceId;
RSemaphore semaphore = redissonClient.getSemaphore(semaphoreKey);
try {
semaphore.trySetPermits(maxConcurrent);
System.out.println("资源 " + resourceId + " 当前可用许可证数: " + semaphore.availablePermits());
// 尝试获取许可证,最多等待5秒
boolean acquired = semaphore.tryAcquire(5, TimeUnit.SECONDS);
if (acquired) {
try {
System.out.println("获取到资源 " + resourceId + " 的访问权限,执行访问任务");
// 执行资源访问任务
accessTask.run();
return true;
} finally {
// 释放许可证
semaphore.release();
System.out.println("释放资源 " + resourceId + " 的访问权限");
}
} else {
System.out.println("获取资源 " + resourceId + " 访问权限超时,当前可用许可证数: " +
semaphore.availablePermits());
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("获取许可证时被中断: " + e.getMessage());
// 尝试释放许可证
try {
semaphore.release();
} catch (Exception releaseException) {
System.err.println("释放许可证时发生异常: " + releaseException.getMessage());
}
return false;
} catch (Exception e) {
System.err.println("资源访问控制时发生异常: " + e.getMessage());
return false;
}
}
/**
* 秒杀系统中的并发控制
*
* @param productId 商品ID
* @param userId 用户ID
* @return 秒杀结果
*/
public boolean flashSale(String productId, String userId) {
// 使用商品ID作为信号量key,限制同时访问该商品的用户数量
String semaphoreKey = "flash_sale:" + productId;
RSemaphore semaphore = redissonClient.getSemaphore(semaphoreKey);
try {
// 设置秒杀活动的并发限制(例如,最多允许100个用户同时参与)
semaphore.trySetPermits(100);
// 尝试获取秒杀资格
boolean hasQualification = semaphore.tryAcquire(2, TimeUnit.SECONDS);
if (!hasQualification) {
System.out.println("用户 " + userId + " 秒杀失败,秒杀资格已满");
return false;
}
try {
// 检查库存
if (checkStock(productId) > 0) {
// 扣减库存
if (decreaseStock(productId)) {
// 创建订单
createOrder(productId, userId);
System.out.println("用户 " + userId + " 秒杀成功,商品: " + productId);
return true;
} else {
System.out.println("用户 " + userId + " 秒杀失败,库存扣减失败");
}
} else {
System.out.println("用户 " + userId + " 秒杀失败,库存不足");
}
} finally {
// 释放秒杀资格
semaphore.release();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("秒杀过程中被中断: " + e.getMessage());
} catch (Exception e) {
System.err.println("秒杀过程中发生异常: " + e.getMessage());
}
return false;
}
/**
* 模拟检查库存
*/
private int checkStock(String productId) {
// 实际应用中这里会查询数据库或缓存
return 10; // 模拟有10个库存
}
/**
* 模拟扣减库存
*/
private boolean decreaseStock(String productId) {
// 实际应用中这里会更新数据库
System.out.println("扣减商品 " + productId + " 的库存");
return true;
}
/**
* 模拟创建订单
*/
private void createOrder(String productId, String userId) {
// 实际应用中这里会创建订单记录
System.out.println("为用户 " + userId + " 创建商品 " + productId + " 的订单");
}
/**
* 异步资源访问
*/
public CompletableFuture<Boolean> asyncResourceAccess(String resourceId, int maxConcurrent, Runnable accessTask) {
return CompletableFuture.supplyAsync(() -> {
return controlResourceAccess(resourceId, maxConcurrent, accessTask);
});
}
}
3. 布隆过滤器 - 高效去重和排查
java
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import java.util.Collection;
/**
* 布隆过滤器生产级应用场景示例
*/
public class BloomFilterScenario {
private final RedissonClient redissonClient;
public BloomFilterScenario(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 防止缓存穿透的布隆过滤器
*
* @param key 要检查的键
* @return 如果键可能存在则返回true,如果确定不存在则返回false
*/
public boolean preventCachePenetration(String key) {
String filterName = "cache_penetration_filter";
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(filterName);
// 初始化布隆过滤器(预计100万个元素,3%误判率)
if (!bloomFilter.isExists()) {
bloomFilter.tryInit(1000000, 0.03);
System.out.println("缓存穿透防护布隆过滤器已初始化");
}
// 首先检查布隆过滤器
if (!bloomFilter.contains(key)) {
// 布隆过滤器确认元素不存在,直接返回,避免查询缓存和数据库
System.out.println("布隆过滤器确认键不存在,跳过缓存和数据库查询: " + key);
return false;
}
System.out.println("布隆过滤器认为键可能存在,继续查询缓存/数据库: " + key);
// 继续查询缓存和数据库...
return true;
}
/**
* URL去重场景
*
* @param url 要检查的URL
* @return 如果URL是新的则返回true,如果是重复的则返回false
*/
public boolean urlDeduplication(String url) {
String filterName = "visited_urls_filter";
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(filterName);
// 初始化布隆过滤器(预计1000万个URL,1%误判率)
if (!bloomFilter.isExists()) {
bloomFilter.tryInit(10000000, 0.01);
System.out.println("URL去重布隆过滤器已初始化");
}
if (!bloomFilter.contains(url)) {
// 首次访问,添加到过滤器
bloomFilter.add(url);
System.out.println("首次访问URL,已添加到布隆过滤器: " + url);
return true;
} else {
System.out.println("URL已访问过,跳过处理: " + url);
return false;
}
}
/**
* 批量添加元素到布隆过滤器
*
* @param filterName 过滤器名称
* @param elements 要添加的元素集合
*/
public void batchAddToBloomFilter(String filterName, Collection<String> elements) {
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(filterName);
// 如果过滤器不存在,使用默认参数创建
if (!bloomFilter.isExists()) {
// 根据元素数量估算参数
long expectedElements = Math.max(elements.size() * 2, 100000L);
bloomFilter.tryInit(expectedElements, 0.03);
System.out.println("布隆过滤器 " + filterName + " 已初始化,预期元素数: " + expectedElements);
}
int addedCount = 0;
for (String element : elements) {
if (bloomFilter.add(element)) {
addedCount++;
}
}
System.out.println("批量添加完成,新增 " + addedCount + " 个元素到过滤器: " + filterName);
}
/**
* 用户ID存在性检查
*
* @param userId 用户ID
* @return 如果用户可能存在则返回true
*/
public boolean checkUserExists(String userId) {
String filterName = "user_exists_filter";
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(filterName);
// 初始化布隆过滤器(预计1000万个用户,3%误判率)
if (!bloomFilter.isExists()) {
bloomFilter.tryInit(10000000, 0.03);
System.out.println("用户存在性检查布隆过滤器已初始化");
}
boolean mightExist = bloomFilter.contains(userId);
System.out.println("用户 " + userId + " 可能存在: " + mightExist);
return mightExist;
}
}
4. 延迟队列 - 定时任务处理
java
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 延迟队列生产级应用场景示例
*/
public class DelayedQueueScenario {
private final RedissonClient redissonClient;
private final ExecutorService executorService;
public DelayedQueueScenario(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
this.executorService = Executors.newFixedThreadPool(10);
}
/**
* 订单超时处理场景
*
* @param orderId 订单ID
* @param timeout 超时时间
* @param unit 时间单位
*/
public void handleOrderTimeout(String orderId, long timeout, TimeUnit unit) {
String queueName = "order_timeout_queue";
RBlockingQueue<String> queue = redissonClient.getBlockingQueue(queueName);
RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(queue);
try {
// 订单创建后timeout时间如果仍未支付,则触发超时处理
delayedQueue.offer(orderId, timeout, unit);
System.out.println("订单 " + orderId + " 已添加到延迟队列,超时时间: " + timeout + " " + unit);
} finally {
// 注意:在实际应用中,延迟队列通常在整个应用程序生命周期内保持
// 这里为了示例简化,但在生产环境中不应立即销毁
}
}
/**
* 启动延迟队列消费者线程
*/
public void startDelayedQueueConsumer() {
String queueName = "order_timeout_queue";
RBlockingQueue<String> queue = redissonClient.getBlockingQueue(queueName);
RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(queue);
// 启动消费者线程
executorService.submit(() -> {
try {
while (!Thread.currentThread().isInterrupted()) {
// 阻塞等待超时订单
String timeoutOrderId = queue.take();
System.out.println("订单超时,执行取消操作: " + timeoutOrderId);
// 在独立线程中处理超时订单,避免阻塞队列消费
executorService.submit(() -> {
processTimeoutOrder(timeoutOrderId);
});
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("延迟队列消费者线程被中断");
} catch (Exception e) {
System.err.println("延迟队列消费过程中发生异常: " + e.getMessage());
}
});
System.out.println("延迟队列消费者已启动");
}
/**
* 处理超时订单
*
* @param orderId 超时订单ID
*/
private void processTimeoutOrder(String orderId) {
try {
// 执行取消订单、释放库存等操作
System.out.println("正在处理超时订单: " + orderId);
// 模拟业务处理
cancelOrder(orderId);
releaseInventory(orderId);
System.out.println("超时订单处理完成: " + orderId);
} catch (Exception e) {
System.err.println("处理超时订单时发生异常,订单ID: " + orderId + ",异常: " + e.getMessage());
}
}
/**
* 订单支付成功后取消延迟任务
*
* @param orderId 订单ID
*/
public boolean cancelOrderTimeout(String orderId) {
String queueName = "order_timeout_queue";
RBlockingQueue<String> queue = redissonClient.getBlockingQueue(queueName);
RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(queue);
// 从延迟队列中移除,避免超时处理
boolean removed = delayedQueue.remove(orderId);
if (removed) {
System.out.println("已取消订单超时处理: " + orderId);
} else {
System.out.println("订单不在延迟队列中,可能已超时处理: " + orderId);
}
return removed;
}
/**
* 关闭资源
*/
public void shutdown() {
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdown();
try {
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
/**
* 模拟取消订单
*/
private void cancelOrder(String orderId) {
// 实际应用中这里会更新订单状态
System.out.println("订单已取消: " + orderId);
}
/**
* 模拟释放库存
*/
private void releaseInventory(String orderId) {
// 实际应用中这里会释放占用的库存
System.out.println("已释放订单库存: " + orderId);
}
}
5. 分布式计数器 - 统计和限流
java
import org.redisson.api.RAtomicLong;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RedissonClient;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* 分布式计数器生产级应用场景示例
*/
public class CounterScenario {
private final RedissonClient redissonClient;
public CounterScenario(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 接口访问限流
*
* @param interfaceName 接口名称
* @param maxRequests 最大请求数
* @param timeUnit 时间单位
* @return 是否允许访问
*/
public boolean interfaceRateLimiting(String interfaceName, long maxRequests, TimeUnit timeUnit) {
String rateLimiterKey = "api_rate_limiter:" + interfaceName;
RRateLimiter rateLimiter = redissonClient.getRateLimiter(rateLimiterKey);
// 配置限流器:在指定时间间隔内最多允许maxRequests个请求
if (!rateLimiter.isExists()) {
RateIntervalUnit intervalUnit;
long rateInterval = 1;
switch (timeUnit) {
case SECONDS:
intervalUnit = RateIntervalUnit.SECONDS;
break;
case MINUTES:
intervalUnit = RateIntervalUnit.MINUTES;
break;
case HOURS:
intervalUnit = RateIntervalUnit.HOURS;
break;
default:
intervalUnit = RateIntervalUnit.SECONDS;
}
rateLimiter.trySetRate(RateType.OVERALL, maxRequests, rateInterval, intervalUnit);
System.out.println("接口 " + interfaceName + " 限流器已设置: " + maxRequests +
" 次/" + timeUnit);
}
// 尝试获取令牌
boolean allowed = rateLimiter.tryAcquire();
if (allowed) {
System.out.println("接口 " + interfaceName + " 访问被允许");
} else {
System.out.println("接口 " + interfaceName + " 访问被限流");
}
return allowed;
}
/**
* 接口访问统计
*
* @param interfaceName 接口名称
* @return 当前访问次数
*/
public long countApiAccess(String interfaceName) {
String counterKey = "api_access_counter:" + interfaceName;
RAtomicLong counter = redissonClient.getAtomicLong(counterKey);
// 原子递增计数器
long count = counter.incrementAndGet();
System.out.println("接口 " + interfaceName + " 访问次数: " + count);
return count;
}
/**
* 分布式ID生成器
*
* @param generatorName 生成器名称
* @param step 步长
* @return 下一个ID
*/
public long generateDistributedId(String generatorName, long step) {
String counterKey = "distributed_id_generator:" + generatorName;
RAtomicLong idGenerator = redissonClient.getAtomicLong(counterKey);
// 原子性地增加step并返回新值
long nextId = idGenerator.addAndGet(step);
System.out.println(generatorName + " 生成的下一个ID: " + nextId);
return nextId;
}
/**
* 简单的分布式ID生成器
*
* @param generatorName 生成器名称
* @return 下一个ID
*/
public long generateNextId(String generatorName) {
return generateDistributedId(generatorName, 1);
}
/**
* 获取计数器当前值
*
* @param counterName 计数器名称
* @return 当前计数值
*/
public long getCurrentCount(String counterName) {
RAtomicLong counter = redissonClient.getAtomicLong(counterName);
return counter.get();
}
/**
* 重置计数器
*
* @param counterName 计数器名称
* @param newValue 新值
*/
public void resetCounter(String counterName, long newValue) {
RAtomicLong counter = redissonClient.getAtomicLong(counterName);
counter.set(newValue);
System.out.println("计数器 " + counterName + " 已重置为: " + newValue);
}
/**
* 带条件更新的计数器操作
*
* @param counterName 计数器名称
* @param expectedValue 期望值
* @param newValue 新值
* @return 更新是否成功
*/
public boolean conditionalUpdate(String counterName, long expectedValue, long newValue) {
RAtomicLong counter = redissonClient.getAtomicLong(counterName);
boolean updated = counter.compareAndSet(expectedValue, newValue);
if (updated) {
System.out.println("计数器 " + counterName + " 条件更新成功: " + expectedValue + " -> " + newValue);
} else {
System.out.println("计数器 " + counterName + " 条件更新失败,当前值: " + counter.get());
}
return updated;
}
/**
* 异步获取计数器值
*
* @param counterName 计数器名称
* @return CompletableFuture表示计数值
*/
public CompletableFuture<Long> getCounterValueAsync(String counterName) {
return CompletableFuture.supplyAsync(() -> {
RAtomicLong counter = redissonClient.getAtomicLong(counterName);
return counter.get();
});
}
}
6. 分布式集合 - 共享数据存储
java
import org.redisson.api.*;
import org.redisson.api.mapreduce.RCollectionMapReduce;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 分布式集合并发级应用场景示例
*/
public class CollectionsScenario {
private final RedissonClient redissonClient;
public CollectionsScenario(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 分布式缓存Map操作
*
* @param cacheName 缓存名称
* @param key 键
* @param value 值
* @param ttl 缓存过期时间
* @return 操作结果
*/
public boolean operateDistributedCache(String cacheName, String key, Object value, long ttl, TimeUnit timeUnit) {
try {
RMap<String, Object> cache = redissonClient.getMap(cacheName);
// 设置带过期时间的键值对
Object oldValue = cache.put(key, value, ttl, timeUnit);
System.out.println("在缓存 " + cacheName + " 中设置: " + key + " = " + value +
",过期时间: " + ttl + " " + timeUnit);
if (oldValue != null) {
System.out.println("替换的旧值: " + oldValue);
}
return true;
} catch (Exception e) {
System.err.println("操作分布式缓存时发生异常: " + e.getMessage());
return false;
}
}
/**
* 在线用户管理
*
* @param userId 用户ID
* @return 操作结果
*/
public boolean manageOnlineUsers(String userId) {
try {
RSet<String> onlineUsers = redissonClient.getSet("online_users");
// 添加用户到在线用户集合
boolean added = onlineUsers.add(userId);
if (added) {
System.out.println("用户 " + userId + " 已上线");
} else {
System.out.println("用户 " + userId + " 已在线");
}
// 获取当前在线用户数
int onlineCount = onlineUsers.size();
System.out.println("当前在线用户数: " + onlineCount);
return added;
} catch (Exception e) {
System.err.println("管理在线用户时发生异常: " + e.getMessage());
return false;
}
}
/**
* 移除在线用户
*
* @param userId 用户ID
* @return 是否成功移除
*/
public boolean removeOnlineUser(String userId) {
try {
RSet<String> onlineUsers = redissonClient.getSet("online_users");
boolean removed = onlineUsers.remove(userId);
if (removed) {
System.out.println("用户 " + userId + " 已下线");
} else {
System.out.println("用户 " + userId + " 不在在线用户列表中");
}
return removed;
} catch (Exception e) {
System.err.println("移除在线用户时发生异常: " + e.getMessage());
return false;
}
}
/**
* 获取所有在线用户
*
* @return 在线用户列表
*/
public List<String> getOnlineUsers() {
try {
RSet<String> onlineUsers = redissonClient.getSet("online_users");
return onlineUsers.readAllSet().stream().toList();
} catch (Exception e) {
System.err.println("获取在线用户列表时发生异常: " + e.getMessage());
return List.of();
}
}
/**
* 操作分布式列表
*
* @param listName 列表名称
* @param elements 要添加的元素
* @return 操作结果
*/
public boolean operateDistributedList(String listName, List<String> elements) {
try {
RList<String> list = redissonClient.getList(listName);
// 批量添加元素
list.addAll(elements);
System.out.println("向列表 " + listName + " 添加 " + elements.size() + " 个元素");
// 获取列表大小
int size = list.size();
System.out.println("列表 " + listName + " 当前大小: " + size);
// 获取列表内容(限制数量以避免大量数据传输)
int maxElementsToShow = Math.min(10, size);
if (size > 0) {
java.util.List<String> subList = list.subList(0, maxElementsToShow);
System.out.println("列表前 " + maxElementsToShow + " 个元素: " + subList);
if (size > maxElementsToShow) {
System.out.println("... 还有 " + (size - maxElementsToShow) + " 个元素");
}
}
return true;
} catch (Exception e) {
System.err.println("操作分布式列表时发生异常: " + e.getMessage());
return false;
}
}
/**
* 批量操作Map
*
* @param mapName Map名称
* @param data 批量数据
* @return 操作结果
*/
public boolean batchOperateMap(String mapName, Map<String, Object> data) {
try {
RMap<String, Object> map = redissonClient.getMap(mapName);
// 批量添加数据
map.putAll(data);
System.out.println("向Map " + mapName + " 批量添加 " + data.size() + " 个键值对");
// 获取Map大小
int size = map.size();
System.out.println("Map " + mapName + " 当前大小: " + size);
return true;
} catch (Exception e) {
System.err.println("批量操作Map时发生异常: " + e.getMessage());
return false;
}
}
/**
* 获取Map的所有键值对
*
* @param mapName Map名称
* @return 所有键值对
*/
public Map<String, Object> getAllMapEntries(String mapName) {
try {
RMap<String, Object> map = redissonClient.getMap(mapName);
return map.readAllMap();
} catch (Exception e) {
System.err.println("获取Map所有键值对时发生异常: " + e.getMessage());
return Map.of();
}
}
/**
* 安全删除Map中的键值对
*
* @param mapName Map名称
* @param key 要删除的键
* @return 是否成功删除
*/
public boolean safeRemoveFromMap(String mapName, String key) {
try {
RMap<String, Object> map = redissonClient.getMap(mapName);
Object removedValue = map.remove(key);
if (removedValue != null) {
System.out.println("从Map " + mapName + " 中删除键: " + key + ",值: " + removedValue);
return true;
} else {
System.out.println("键 " + key + " 在Map " + mapName + " 中不存在");
return false;
}
} catch (Exception e) {
System.err.println("安全删除Map键值对时发生异常: " + e.getMessage());
return false;
}
}
}
7. 发布/订阅 - 实时消息通知
java
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 发布/订阅生产级应用场景示例
*/
public class PubSubScenario {
private final RedissonClient redissonClient;
private final ExecutorService executorService;
public PubSubScenario(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
this.executorService = Executors.newCachedThreadPool();
}
/**
* 订阅系统通知
*
* @param topicName 主题名称
* @param notificationHandler 通知处理器
* @return 监听器ID
*/
public int subscribeSystemNotifications(String topicName, java.util.function.Consumer<String> notificationHandler) {
RTopic topic = redissonClient.getTopic(topicName);
// 添加消息监听器
int listenerId = topic.addListener(String.class, new MessageListener<String>() {
@Override
public void onMessage(CharSequence channel, String message) {
System.out.println("收到系统通知 - 频道: " + channel + ",消息: " + message);
// 在独立线程中处理消息,避免阻塞Redisson的消息处理线程
executorService.submit(() -> {
try {
notificationHandler.accept(message);
} catch (Exception e) {
System.err.println("处理系统通知时发生异常: " + e.getMessage());
}
});
}
});
System.out.println("已订阅系统通知主题: " + topicName + ",监听器ID: " + listenerId);
return listenerId;
}
/**
* 发布系统通知
*
* @param topicName 主题名称
* @param message 通知消息
* @return 接收者数量
*/
public long publishSystemNotification(String topicName, String message) {
try {
RTopic topic = redissonClient.getTopic(topicName);
// 发布消息
long receivers = topic.publish(message);
System.out.println("系统通知已发布 - 主题: " + topicName +
",消息: " + message +
",接收者数量: " + receivers);
return receivers;
} catch (Exception e) {
System.err.println("发布系统通知时发生异常: " + e.getMessage());
return 0;
}
}
/**
* 异步发布系统通知
*
* @param topicName 主题名称
* @param message 通知消息
* @return CompletableFuture表示发布结果
*/
public CompletableFuture<Long> publishSystemNotificationAsync(String topicName, String message) {
return CompletableFuture.supplyAsync(() -> {
return publishSystemNotification(topicName, message);
}, executorService);
}
/**
* 订单状态变更通知场景
*
* @param orderId 订单ID
* @param newStatus 新状态
*/
public void notifyOrderStatusChange(String orderId, String newStatus) {
String topicName = "order_status_change";
String message = String.format("订单 %s 状态变更为 %s", orderId, newStatus);
publishSystemNotification(topicName, message);
}
/**
* 用户登录通知场景
*
* @param userId 用户ID
* @param loginTime 登录时间
*/
public void notifyUserLogin(String userId, long loginTime) {
String topicName = "user_login";
String message = String.format("用户 %s 于 %d 登录", userId, loginTime);
publishSystemNotification(topicName, message);
}
/**
* 系统维护通知场景
*
* @param maintenanceTime 维护时间
* @param duration 维护时长
*/
public void notifySystemMaintenance(long maintenanceTime, long duration) {
String topicName = "system_maintenance";
String message = String.format("系统将于 %d 开始维护,预计持续 %d 秒", maintenanceTime, duration);
publishSystemNotification(topicName, message);
}
/**
* 移除消息监听器
*
* @param topicName 主题名称
* @param listenerId 监听器ID
*/
public void removeMessageListener(String topicName, int listenerId) {
RTopic topic = redissonClient.getTopic(topicName);
topic.removeListener(listenerId);
System.out.println("已移除监听器,ID: " + listenerId + ",主题: " + topicName);
}
/**
* 关闭资源
*/
public void shutdown() {
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdown();
try {
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
}
底层原理详解
1. 分布式锁实现原理 🧩
Redisson的分布式锁就像一个智能"门卫",它的实现原理非常巧妙:
- 获取锁 : 使用Redis的
SET key value NX EX seconds命令,就像一个"先到先得"的机制,确保只有在key不存在时才设置成功,实现原子性操作 - Watchdog机制: Redisson使用后台定时任务(看门狗),每过锁过期时间的1/3就自动续期,就像给锁装了"永不断电"的电池,防止业务执行时间过长导致锁意外释放
- 可重入性: 通过Redis Hash结构记录线程ID和重入次数,让同一个"客人"可以多次进入"房间"
- 原子性操作: 使用Lua脚本保证多个Redis命令的原子执行,就像一个"密闭房间",确保操作的完整性
- 锁释放: 只有锁的持有者才能释放锁(通过Lua脚本验证),防止"张冠李戴"
- RedLock算法: 在多Redis节点环境下,需要半数以上节点获取锁才算成功,就像"少数服从多数"的民主机制
2. 信号量实现原理 🚦
信号量就像一个智能"交通灯"控制器:
- 许可证管理: 使用Redis的原子操作来管理许可证数量,确保许可证计数的准确性
- 阻塞获取: 当许可证不足时,使用Redis的发布/订阅机制实现优雅的阻塞等待,就像"排队等座"一样
- 释放许可证: 当许可证被释放时,自动通知等待的线程,实现资源的有效分配
3. 延迟队列实现原理 ⏰
延迟队列就像一个智能"闹钟":
- 时间轮算法: Redisson使用Sorted Set (ZSET) 按时间戳顺序存储延迟元素,就像按照"闹钟时间"排列的闹钟阵列
- 后台轮询: 维护一个后台线程不断轮询ZSET,将到期元素转移到底层队列,就像"时间守护者"时刻监测
- 原子转移: 使用Lua脚本确保延迟元素到普通队列的转移是原子操作,避免"时间错乱"
4. 布隆过滤器实现原理 🧺
布隆过滤器就像一个神奇的"筛子":
- 多Hash函数: 使用多个Hash函数对元素进行计算,就像用多个"筛孔"定位元素位置
- BitSet存储: 使用Redis的String类型模拟BitSet,每个bit位代表一个可能的元素位置
- 误判率控制: 通过调整Hash函数个数和BitSet大小来控制误判率,就像调整"筛子精度"
- 空间效率: 相比传统集合,布隆过滤器占用空间极小,但存在少量误判,是"空间换时间"的典型应用
5. 发布/订阅机制 📡
发布/订阅就像一个高效的"广播站":
- Redis PUB/SUB: 基于Redis的原生发布/订阅功能实现,提供实时消息传递
- 模式匹配: 支持使用通配符进行频道模式匹配,让消息传递更灵活
- 消息可靠性: 提供同步和异步两种消息处理方式,满足不同场景需求
- 连接管理: 自动处理连接断开和重连,确保消息传递的可靠性
6. 序列化与反序列化 📦
序列化就像数据的"变身术":
- 默认策略: 使用Jackson JSON序列化,保证数据的可读性和跨语言兼容性
- 多种策略: 支持Kryo、FST、Smile、CBOR等多种序列化方式,满足不同性能需求
- 性能对比: Kryo和FST序列化速度快、体积小,但Jackson兼容性更好
- 自定义序列化: 可通过配置自定义序列化策略,满足特殊业务需求
性能优化建议 🚀
-
合理设置连接池大小 💧 - 就像给水管设置合适的口径,连接池太小会造成"供水不足"(请求排队),太大则会造成"资源浪费"(连接闲置),需要根据实际业务流量来"精确调节"
-
使用本地缓存减少Redis访问 🏠 - 就像在家中储备日常用品一样,频繁访问的数据可以放在本地缓存中,减少网络往返的开销,让访问如"近水楼台先得月"
-
批量操作提高效率 📦 - 就像购物时一次性购买多件商品比多次单独购买更高效一样,批量操作可以显著减少网络通信次数,提升整体性能
-
合理设置锁的超时时间 ⏱️ - 就像停车场的计时收费一样,锁的超时时间设置要恰到好处,太短可能导致业务未完成就被释放,太长则可能造成资源长时间占用
-
选择合适的序列化方式 📝 - 就像选择不同的信封一样,不同的序列化方式有不同的特点:Jackson兼容性好但体积大,Kryo和FST速度快但适用范围有限,要根据场景选择
常见问题与最佳实践
1. 锁的可重入性
java
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
/**
* 分布式锁可重入性生产级示例
*/
public class ReentrantLockExample {
private final RedissonClient redissonClient;
public ReentrantLockExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 演示分布式锁的可重入性
*
* @param lockKey 锁的key
*/
public void demonstrateReentrantLock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
try {
// 第一次获取锁
lock.lock(30, TimeUnit.SECONDS);
System.out.println("第一次获取锁成功: " + lockKey);
try {
// 同一线程可以多次获取同一把锁(可重入)
lock.lock(30, TimeUnit.SECONDS);
System.out.println("第二次获取锁成功(可重入): " + lockKey);
try {
lock.lock(30, TimeUnit.SECONDS);
System.out.println("第三次获取锁成功(可重入): " + lockKey);
// 执行业务逻辑
System.out.println("执行业务逻辑...");
} finally {
// 需要对应次数的unlock操作
lock.unlock();
System.out.println("第三次释放锁: " + lockKey + ",锁仍被持有: " + lock.isLocked());
}
} finally {
// 第二次释放锁
lock.unlock();
System.out.println("第二次释放锁: " + lockKey + ",锁仍被持有: " + lock.isLocked());
}
} finally {
// 最后一次释放锁,真正释放锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
System.out.println("第一次释放锁: " + lockKey + ",锁已完全释放: " + !lock.isLocked());
}
}
}
/**
* 安全的可重入锁操作
*
* @param lockKey 锁的key
* @param businessLogic 业务逻辑
* @return 操作结果
*/
public boolean safeReentrantOperation(String lockKey, Runnable businessLogic) {
RLock lock = redissonClient.getLock(lockKey);
int lockCount = 0; // 记录加锁次数
try {
// 获取主锁
lock.lock(30, TimeUnit.SECONDS);
lockCount++;
// 在业务逻辑中可能需要再次获取锁
executeNestedOperation(lock, businessLogic);
return true;
} catch (Exception e) {
System.err.println("可重入锁操作异常: " + e.getMessage());
return false;
} finally {
// 释放所有层级的锁
for (int i = 0; i < lockCount; i++) {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
/**
* 嵌套操作,可能需要再次获取锁
*/
private void executeNestedOperation(RLock lock, Runnable businessLogic) {
// 模拟在业务逻辑中需要再次获取锁的情况
if (lock.isHeldByCurrentThread()) {
// 同一线程可以再次获取锁
lock.lock();
try {
// 执行业务逻辑
businessLogic.run();
} finally {
lock.unlock(); // 对应的解锁操作
}
}
}
}
2. 死锁预防与超时处理
java
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* 死锁预防与超时处理生产级示例
*/
public class DeadlockPreventionExample {
private final RedissonClient redissonClient;
public DeadlockPreventionExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 使用带超时的锁获取,防止死锁
*
* @param lockKey 锁的key
* @param businessLogic 业务逻辑
* @return 操作结果
*/
public boolean preventDeadlockWithTimeout(String lockKey, Runnable businessLogic) {
RLock lock = redissonClient.getLock(lockKey);
try {
// 使用tryLock设置等待时间和锁持有时间,防止无限等待和死锁
boolean acquired = lock.tryLock(10, 30, TimeUnit.SECONDS);
if (acquired) {
try {
System.out.println("获取锁成功: " + lockKey);
// 执行业务逻辑
businessLogic.run();
return true;
} finally {
// 确保锁被释放
if (lock.isHeldByCurrentThread()) {
lock.unlock();
System.out.println("释放锁: " + lockKey);
}
}
} else {
System.out.println("获取锁超时: " + lockKey);
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("获取锁时被中断: " + e.getMessage());
// 恢复中断状态并确保锁被释放
if (lock != null && lock.isHeldByCurrentThread()) {
try {
lock.unlock();
} catch (Exception unlockException) {
System.err.println("释放锁时发生异常: " + unlockException.getMessage());
}
}
return false;
} catch (Exception e) {
System.err.println("锁操作异常: " + e.getMessage());
return false;
}
}
/**
* 异步锁操作与超时处理
*
* @param lockKey 锁的key
* @param businessLogic 业务逻辑
* @param timeoutSeconds 超时时间(秒)
* @return CompletableFuture表示操作结果
*/
public CompletableFuture<Boolean> asyncLockOperation(String lockKey,
Runnable businessLogic,
long timeoutSeconds) {
return CompletableFuture.supplyAsync(() -> {
RLock lock = redissonClient.getLock(lockKey);
try {
// 使用看门狗机制,自动续期
lock.lock(timeoutSeconds, TimeUnit.SECONDS);
try {
System.out.println("异步操作获取锁成功: " + lockKey);
businessLogic.run();
return true;
} finally {
if (lock != null && lock.isHeldByCurrentThread()) {
lock.unlock();
System.out.println("异步操作释放锁: " + lockKey);
}
}
} catch (Exception e) {
System.err.println("异步锁操作异常: " + e.getMessage());
return false;
}
});
}
/**
* 多重锁的安全操作
*
* @param lockKeys 锁的keys
* @param businessLogic 业务逻辑
* @return 操作结果
*/
public boolean multiLockOperation(String[] lockKeys, Runnable businessLogic) {
if (lockKeys == null || lockKeys.length == 0) {
System.out.println("没有提供锁keys");
return false;
}
java.util.List<RLock> locks = new java.util.ArrayList<>();
for (String lockKey : lockKeys) {
locks.add(redissonClient.getLock(lockKey));
}
RLock multiLock = redissonClient.getMultiLock(locks.toArray(new RLock[0]));
try {
// 获取多重锁,设置等待时间和持有时间
boolean acquired = multiLock.tryLock(10, 30, TimeUnit.SECONDS);
if (acquired) {
try {
System.out.println("获取多重锁成功: " + String.join(", ", lockKeys));
businessLogic.run();
return true;
} finally {
// 释放多重锁
if (multiLock.isHeldByCurrentThread()) {
multiLock.unlock();
System.out.println("释放多重锁: " + String.join(", ", lockKeys));
}
}
} else {
System.out.println("获取多重锁超时: " + String.join(", ", lockKeys));
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("获取多重锁时被中断: " + e.getMessage());
if (multiLock != null && multiLock.isHeldByCurrentThread()) {
try {
multiLock.unlock();
} catch (Exception unlockException) {
System.err.println("释放多重锁时发生异常: " + unlockException.getMessage());
}
}
return false;
} catch (Exception e) {
System.err.println("多重锁操作异常: " + e.getMessage());
return false;
}
}
}
3. 客户端资源管理
java
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Redisson客户端资源管理生产级示例
*/
public class ResourceManagerExample {
/**
* 正确的Redisson客户端创建和关闭
*/
public static class RedissonClientManager {
private RedissonClient redissonClient;
private ExecutorService executorService;
public void initialize() {
try {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379")
.setConnectionPoolSize(100)
.setMinimumIdle(10)
.setConnectTimeout(10000)
.setTimeout(3000);
config.setNettyThreads(32);
// 创建Redisson客户端
this.redissonClient = Redisson.create(config);
this.executorService = Executors.newCachedThreadPool();
System.out.println("Redisson客户端已初始化");
} catch (Exception e) {
System.err.println("初始化Redisson客户端失败: " + e.getMessage());
throw new RuntimeException("Redisson客户端初始化失败", e);
}
}
public RedissonClient getRedissonClient() {
if (redissonClient == null || redissonClient.isShutdown()) {
throw new IllegalStateException("Redisson客户端未初始化或已关闭");
}
return redissonClient;
}
/**
* 安全关闭Redisson客户端
*/
public void shutdown() {
// 首先关闭线程池
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdown();
try {
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
executorService.shutdownNow();
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
System.err.println("线程池未能正常关闭");
}
}
} catch (InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
// 然后关闭Redisson客户端
if (redissonClient != null && !redissonClient.isShutdown()) {
try {
// 优雅关闭,等待所有操作完成
redissonClient.shutdown(2, 5, TimeUnit.SECONDS);
System.out.println("Redisson客户端已关闭");
} catch (Exception e) {
System.err.println("关闭Redisson客户端时发生异常: " + e.getMessage());
}
}
}
}
/**
* 使用示例
*/
public static void main(String[] args) {
RedissonClientManager manager = new RedissonClientManager();
try {
manager.initialize();
// 使用Redisson客户端
RedissonClient redisson = manager.getRedissonClient();
System.out.println("Redisson客户端状态: " + (redisson.isShutdown() ? "已关闭" : "运行中"));
// 执行业务操作...
} finally {
// 确保在应用结束时关闭客户端
manager.shutdown();
}
}
}
Redisson就像分布式系统中的"瑞士军刀",是一个功能强大且易于使用的Redis Java客户端!它特别适合在分布式系统中解决并发控制、数据共享等复杂问题。通过合理使用其提供的各种分布式对象和功能,并遵循生产级最佳实践,就像有了"分布式开发的超级助手",可以大大简化分布式应用的开发,同时确保系统的稳定性和可靠性。让我们一起用Redisson打造更稳定、更高效的分布式系统吧! 🎉