使用Redisson操作分布式队列的注意事项

先说结论:
使用Redisson提供的RedissonPriorityQueue时, 比较操作不使用对象的equals, 而是使用compare比较.

最近做一个定时任务的服务, 需要用到分布式优先级队列, 选择了Redisson库.
Redisson的队列有很多, 也都继承了java包的Queue接口, 看起来非常方便.
修改代码后, 发现一个很奇怪的问题, 将一个元素加进去之后, 移除不了, remove 返回了false.
元素是一个自定义的类, 重写了equals和hashcode, 所以应该没有什么问题, 使用java con包中的队列一切正常.
这就很奇怪了, Redisson虽然实现了接口, 但预期行为不对, 没有通过equals函数来比较元素是否相同,
通过代码分析RedissonPriorityQueue来查找原因(只显示关键代码):

    @Override
    public boolean remove(Object value) {
            BinarySearchResult<V> res = binarySearch((V) value, codec);
            remove((int) res.getIndex());
    }

上面的remove函数显示使用binarySearch找到元素, 然后删除它

    public BinarySearchResult<V> binarySearch(V value, Codec codec) {
          //调用比较器
            int cmp = comparator.compare(value, res);
            if (cmp == 0) {
                //...
            } else if (cmp < 0) {
                // ...
            } else {
                // ...
            }
        }
    }

上面的代码表示通过 comparator.compare比较两个元素, 返回元素在队列中的位置

  //比较器代码
   private Comparator<? super V> comparator = NaturalComparator.NATURAL_ORDER;
      private static class NaturalComparator<V> implements Comparator<V>, Serializable {

        private static final long serialVersionUID = 7207038068494060240L;

        static final NaturalComparator NATURAL_ORDER = new NaturalComparator();

        public int compare(V c1, V c2) {
            Comparable<Object> c1co = (Comparable<Object>) c1;
            Comparable<Object> c2co = (Comparable<Object>) c2;
            return c1co.compareTo(c2co);
        }

    }

可以看到比较器最终调用了c1co.compareTo(c2co)来比较两个元素.
通常来说, compare函数是比较两个元素的优先级, 而不是比较两个元素内容是否相同的, 但RedissonPriorityQueue打破常规, 不但使用compare来比较优先级, 也同样用来比较元素是否相同.
所以要非常注意compare函数的实现, 比如一个任务(任务名唯一标识一个任务, 时间作为优先级), 可以这样写:

    @Override
    public int compareTo(TaskNode o) {
        if (getName().equals(o.getName())) {
            //名称相同, 说明是同一个任务
            return 0;
        }
        //比较延时
        long diffMs = getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS);
        if (diffMs == 0) {
            //延时相同,比较名称
            return getName().compareTo(o.getName());
        }
        return diffMs > 0 ? 1 : -1;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值