并发引起的java.lang.NullPointerException

时间:2023-01-19 21:31:35

问题背景:

我有一段程序,大量地、并发地发送SNMP告警。这里所谓的并发,就是有很多的定时任务(java.util.Timer),它们行为独立,各自创建SNMPTrap实例,各自通过SNMPTrap 发SNMP告警。


问题描述:

多个Timer长时间(月级)运行时,经常莫名奇妙某个Timer就死掉了,死掉前抛出java.lang.NullPointerException。


问题发现:

经过分析,发现集中、大量、并发地创建SNMPTrap实例时,不同Timer线程虽然各自执行其new SNMPTrap()语句,但在并发情况下,如果两个new语句执行时间足够近,会得到同一份(内存地址相同的)SNMPTrap实例。


我是怎么发现这个问题的呢?通过分析空指针发生时的日志,发现在抛出java.lang.NullPointerException的日志前面,总会出现两次或多次的类似下面的打印信息:

……

org.snmp4j.Snmp@1dd49247
……
org.snmp4j.Snmp@1dd49247

……

java.lang.NullPointerException

……

@之前是类的全限定类名,@之后是类实例的hashCode()值——这个值的默认实现,是根据类实例的内存地址计算出来的。亦即虽然在不同的线程中new了两个实例,但因为时间间隔太近,两份实例指向了同一个内存地址……于是就乱套了,抛出了空指针异常(在这里面,GC的不定时执行可能也起了一定作用)。


问题解决:

重用SNMPTrap,不在大并发的Timer线程中new其实例 。