java.lang.NumberFormatException: multiple points
背景
在接收MQ消息,并且持久化到数据库的时候出现的报错
[2019-03-06 11:15:12:261 CST] ERROR com. . .bridge.rmq.RocketMqMessageCommonServiceImpl.receiveFromScm(RocketMqMessageCommonServiceImpl.java:253) : rocket msgInfo:{"body":{"msgContent":"YKOZLzIhPNU8+jL75MfzOxYTRNpWLukccQgw2UYA0UoXi8JWJ+jUnfn/Ilyqwao1rbUwERkyBT+JWiP5sxlArGgI6gZZOaAJ9ZZrYsgtxtcIChaDhs49ycKcwmnW7HxdVuum1XqBp+LIVhZwpOQ="},"head":{"ifIdentify":"P1-3","ifVersion":"5.0","msgId":"125ce895-613e-41bf-a2c2-494cc8e1864c","msgSendTime":"2019-03-06 11:15:01","shop":"HKREEBOK","sign":"qCEq7DDevJ35e6ZoS/CNyYpvcEOieMsN+28aReDy0dzhTBlXd8a0wfdskrZ5CaV5dE2nrn3pXSsEVwe25TPUHw=="}} java.lang.NumberFormatException: multiple points at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1110) at java.lang.Double.parseDouble(Double.java:540) at java.text.DigitList.getDouble(DigitList.java:168) at java.text.DecimalFormat.parse(DecimalFormat.java:1321) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2088) at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455) at java.text.DateFormat.parse(DateFormat.java:355) at loxia.utils.DateUtil.parse(DateUtil.java:80) at com.bridge.rmq.RocketMqMessageCommonServiceImpl.receiveFromScm(RocketMqMessageCommonServiceImpl.java:223) at com.bridge.rmq.RocketMqMessageCommonServiceImpl.rocketMqReceiveFromScm(RocketMqMessageCommonServiceImpl.java:187) at sun.reflect.GeneratedMethodAccessor516.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com. .scm.baseservice.message.rocketmq.service.MsgTranscationManagerImpl.businessProcess(MsgTranscationManagerImpl.java:182) at com. .scm.baseservice.message.rocketmq.service.M sgTranscationManagerImpl$$FastClassBySpringCGLIB$$6e604685.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:701) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:633) at com. .scm.baseservice.message.rocketmq.service.MsgTranscationManagerImpl$$EnhancerBySpringCGLIB$$bf38f53d.businessProcess(<generated>) at com. .scm.baseservice.message.rocketmq.service.handle.MessageHandler.excuteHandle(MessageHandler.java:271) at com. .scm.baseservice.message.rocketmq.service.handle.MessageHandler.handle(MessageHandler.java:185) at com. .scm.baseservice.message.rocketmq.service.init.RocketMQConcurrentlyConsumerInit$1.consumeMessage(RocketMQConcurrentlyConsumerInit.java:224) at org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService$ConsumeRequest.run(ConsumeMessageConcurrentlyService.java:419) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745)
发现
-
总是出现数据在MQ客户端显示已经被消费了,但是并没有持久化到数据库的问题
-
问后端要了MessageID去查log,最终发现,在处理数据的时候出现了这个错误
查找解决方案
查看报错,最开始觉得是数据格式出错,也是因为接受MQ这套机制很久就已经定义好的,基本不会有问题。
然而发现是:
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
查代码:
public static Date parse(String str, String pattern) throws ParseException { DateFormat df = dateFormatCache.get(pattern); if(df == null){ df = new SimpleDateFormat(pattern); dateFormatCache.put(pattern, df); } return df.parse(str); }
使用了
new SimpleDateFormat(pattern)
而SimpleDateFormat(pattern)
是线程不安全的,当有大量数据过来可能会出现,在处理多条数据的时候使用的同一个simpleDateFormat
导致报错最终解决方案
-
使用
ThreadLocal
//使用线程安全的ThreadLocal static ThreadLocal<DateFormat> testDateFormat = new ThreadLocal<DateFormat>(){ @Override protected SimpleDateFormat initialValue(){ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; private static Date dateParse(String dateStr) throws ParseException { return testDateFormat.get().parse(dateStr); }
-
使用java8的
DateTimeFormatter
private static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-