问题

Nov 21, 2016 11:46:25 AM org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer invokeErrorHandler
WARNING: Execution of Rabbit message listener failed, and no ErrorHandler has been set.
org.springframework.amqp.rabbit.listener.ListenerExecutionFailedException: Listener method 'dequeue' threw exception
	at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.invokeListenerMethod(MessageListenerAdapter.java:443)
	at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:344)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:546)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:472)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:58)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:107)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:608)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:454)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:471)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:455)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$300(SimpleMessageListenerContainer.java:58)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:548)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
	at java.util.TimSort.mergeLo(TimSort.java:747)
	at java.util.TimSort.mergeAt(TimSort.java:483)
	at java.util.TimSort.mergeCollapse(TimSort.java:410)
	at java.util.TimSort.sort(TimSort.java:214)
	at java.util.TimSort.sort(TimSort.java:173)
	at java.util.Arrays.sort(Arrays.java:659)
	at java.util.Collections.sort(Collections.java:217)
	at com.uniweibov2.callcenter.assign.engine.impl.CcLastAssignTimePriorityAssignEngine.priorityAssign(CcLastAssignTimePriorityAssignEngine.java:44)
	at com.uniweibov2.callcenter.CcAssignEngine.assignCommon(CcAssignEngine.java:119)
	at com.uniweibov2.callcenter.CcAssignEngine.assign(CcAssignEngine.java:83)
	at com.uniweibov2.callcenter.service.CcRouterService.newSessionRedisWithDequeue(CcRouterService.java:163)
	at com.uniweibov2.callcenter.CcRouter.dequeueSessionMsg(CcRouter.java:238)
	at com.uniweibov2.callcenter.mq.listener.CCSessionMsgListener.manualDequeue(CCSessionMsgListener.java:107)
	at com.uniweibov2.callcenter.mq.listener.CCSessionMsgListener.dequeue(CCSessionMsgListener.java:135)
	at sun.reflect.GeneratedMethodAccessor123.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:273)
	at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.invokeListenerMethod(MessageListenerAdapter.java:437)
	... 12 more

有问题的Java代码

private static class CcLastAssignTimeComparator implements Comparator<CCUserConfig>, Serializable {  
	         @Override  
	         public int compare(CCUserConfig o1, CCUserConfig o2) {  
                    long redisSizeA = o1.getLastAssignTime();  
                    long redisSizeB = o2.getLastAssignTime();  
                    return (int) (redisSizeA - redisSizeB);
             }
}

原因

这自己写的代码,也太挫了。在公司有同事指出:强制将long转换为int,导致溢出。从而不满足比较器的传递性。这个异常,是在JDK1.7及之后的版本才会抛出的.

同事的原话:

举个例子,无溢出情况下,a > b return positive, b > c return positive, 但当a - c 溢出了,a > c return negative

重现

package com.github.emacsist;

import java.util.*;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
        Random r = new Random(System.currentTimeMillis());
        int n = 800;
        List<Person> l = new ArrayList<>(n);
        for (int i = 0; i < n; i++) {
            Person p = new Person();
            if (i % 11 == 0) {
                p.setAge(System.currentTimeMillis()+Integer.MAX_VALUE);
            } else {
                p.setAge(System.currentTimeMillis()-10 * r.nextInt(10));
            }
            l.add(p);
        }
        System.out.println("befor " + l);
        Collections.sort(l, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return (int)(o1.getAge()-o2.getAge());
            }
        });
        System.out.println("after " + l);
    }

    public static class Person {
        private long age;

        public long getAge() {
            return age;
        }

        public void setAge(long age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return String.valueOf(getAge());
        }
    }
}

输出结果:(如果没有出现,那就执行多几次即可)

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
	at java.util.TimSort.mergeHi(TimSort.java:899)
	at java.util.TimSort.mergeAt(TimSort.java:516)
	at java.util.TimSort.mergeCollapse(TimSort.java:441)
	at java.util.TimSort.sort(TimSort.java:245)
	at java.util.Arrays.sort(Arrays.java:1512)
	at java.util.ArrayList.sort(ArrayList.java:1454)
	at java.util.Collections.sort(Collections.java:175)
	at com.github.emacsist.App.main(App.java:23)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Process finished with exit code 1

解决

 // ASC
        Collections.sort(l, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                if(o1 == null && o2 == null) {
                    return 0;
                }

                //这个根据自己的情况,null到底是在最前,还是最后
                if(o1 == null) {
                    return -1;
                }
                if(o2 == null) {
                    return 1;
                }
                if(o1.getAge() > o2.getAge()) {
                    return 1;
                }
                if(o2.getAge() > o1.getAge()) {
                    return -1;
                }
                return 0;
            }
        });

注意

  1. 最好习惯返回1,0,-1
  2. 如果不这样子,两个数在进行比较时,须保证是无损失精度的比较。(如果是浮点数,最好使用 Double.compare() 之类的方法来比较)
  3. 在JDK1.7及之后版本里,必须要保证如果它们是两等的话,那应该要返回0.