RedisTemplate实现的分布式锁疑似线程不安全的问题

发布于 2022-09-11 23:07:47 字数 3608 浏览 20 评论 0

在测试环境没有复现,上生产出现这样的问题频率好像还挺高,spring-data-redis版本1.4.2
异常如下:

java.lang.ClassCastException: java.lang.Long cannot be cast to [B
        at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:181) ~[jedis-2.6.2.jar:?]
        at redis.clients.jedis.Jedis.set(Jedis.java:79) ~[jedis-2.6.2.jar:?]
        at com.xxx.locks.DistributedLock$1.doInRedis(DistributedLock.java:45) ~[xxx-common-1.0-SNAPSHOT.jar:?]
        at com.xxx.locks.DistributedLock$1.doInRedis(DistributedLock.java:39) ~[xxx-common-1.0-SNAPSHOT.jar:?]
        at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:190) ~[spring-data-redis-1.4.2.RELEASE.jar:1.4.2.RELEASE]
        at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:152) ~[spring-data-redis-1.4.2.RELEASE.jar:1.4.2.RELEASE]
        at com.xxx.locks.DistributedLock.lock(DistributedLock.java:39) [xxx-common-1.0-SNAPSHOT.jar:?]
        at com.xxx.kafka.consumer.EmployeeDataConsumerListener.onMessage(EmployeeDataConsumerListener.java:70) [xxx-service-1.0-SNAPSHOT.jar:?]
        at com.xxx.kafka.api.consume.KafkaConsumer$ConsumeTask.run(KafkaConsumer.java:247) [xxx.kafka-api-core-1.15.1.jar:?]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_172-ea]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_172-ea]

废话不多说这是我的实现代码:

public boolean lock(String key, String requestId) {
        String lockResult = "";
        try {
            lockResult = (String) iRedisCache.getRedisTemplate().execute(new RedisCallback<String>() {
                @Override
                public String doInRedis(RedisConnection redisConnection) {
                    Object nativeConnection = redisConnection.getNativeConnection();
                    String result = "";
                    if (nativeConnection instanceof JedisCommands) {
                        result = ((JedisCommands) nativeConnection).set(key, requestId, "NX", "EX",
                                DISTRIBUTED_LOCK_SECONDS_TIME);
                    }

                    return result;
                }
            }, true);
        } catch (Exception e) {
            log.error("{}" ,e.getMessage(), e);
            
        }
        return "OK".equals(lockResult);
    }

    public void releaseLock(String key, String requestId) {
        try {
            iRedisCache.getRedisTemplate().execute(new RedisCallback<String>() {
                @Override
                public String doInRedis(RedisConnection redisConnection) {
                    Jedis jedis = (Jedis) redisConnection.getNativeConnection();
                    final String script = "if redis.call(\"get\",\"" + key + "\") == \"" + requestId + "\"then  " +
                            "return redis.call(\"del\",\"" + key + "\") else return 0 end ";
                    Long effectRows = (Long) jedis.eval(script);
                    return "OK";
                }
            }, true);
        } catch (Exception e) {
            log.error("{}" ,e.getMessage(), e);
        }
    }

分布式锁在消费kafka时针对用户id加锁使用:

 boolean getLock = distributedLock.lock(key, requestId);
                while (!getLock) {
                    Thread.sleep(DistributedLock.THREAD_WAIT_TIME);
                    getLock = distributedLock.lock(key, requestId);
                }
                if (getLock) {
                    //do something
                    distributedLock.releaseLock(key, requestId);
                }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

余生一个溪 2022-09-18 23:07:47

jredis的connection对象有个buffer用来缓存数据,但是当出现异常的时候,里面的buffer数据不会被清除,而是直接把这个redisConnection还给连接池,所以要手动捕获异常销毁掉这个链接,不然其他线程拿到就会报你这个错误,网上很多类似的问题,你可以搜搜看。另外redis分布式锁建议使用redisson,同时也建议redis客户端使用lettuce,别用jredis

不美如何 2022-09-18 23:07:47

释放锁的时候有java.Lang.String不能转Long类型的CastException

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文