我有以下代码:
jedis.mget(objects.toArray(new String[objects.size()]));
其中对象是字符串列表。代码在大多数情况下运行良好。但出乎意料地提出了以下异常。
java.lang.ClassCastException: [B cannot be cast to java.util.List
at redis.clients.jedis.Connection.getBinaryMultiBulkReply(Connection.java:221)
at redis.clients.jedis.Connection.getMultiBulkReply(Connection.java:214)
at redis.clients.jedis.Jedis.mget(Jedis.java:383)
如果我再次运行相同的代码,它使用相同的数据运行良好。无法理解此类问题的原因。
TL;DR
Jedis 实例不是线程安全的,跨多个线程调用 Jedis 实例将导致这些类型的错误。尝试切换为使用JedisPool
来管理连接的创建。
解释
我看到了这些完全相同的异常,在试图找出问题时,我在 Jedis 项目中遇到了类似的问题,解释 Jedis 不是线程安全的。
由于我在搜索相同的异常时发现了这个问题,我将分享我的特定案例的一些细节,以便对未来的读者有所帮助。
在我的特殊情况下,我使用 Spring Data Redis 中的RedisTemplate
调用 SCAN
命令。我正在对连接生命周期之外生成的Cursor
进行调用。
我的原始代码看起来像这样。
public Long size() {
Cursor<byte[]> scan = redisTemplate.execute((RedisConnection connection) -> connection.scan(ScanOptions.scanOptions().match(prefix + "*").build()));
AtomicLong count = new AtomicLong();
scan.forEachRemaining(bytes -> count.getAndIncrement());
return count.get();
}
经过一个小的更改后,我发现正确的方法是简单地在执行 lambda 内移动光标交互。
public Long size() {
return redisTemplate.execute((RedisConnection connection) -> {
Cursor<byte[]> scan = connection.scan(ScanOptions.scanOptions().match(prefix + "*").build());
AtomicLong count = new AtomicLong();
scan.forEachRemaining(bytes -> count.getAndIncrement());
return count.get();
});
}