一天,同事抛给我一个线上崩溃。堆栈如下(复现的代码)
1 | java.lang.NullPointerException |
相应代码如下:
1 | private static AtomicBoolean sIsExecuting = new AtomicBoolean(false); |
崩在 sTimer.purge()
这一行。
显然是多线程导致的,查看调用problematicMethod
的地方,果然是在不同线程里。首先AtomicBoolean
的用法不对,起不到应有的作用,多个线程仍然可能进入这个方法体。第二,由于第一个问题,判断了sTimer != null
并不能保证调用sTimer.cancel()
及后的方法时sTimer
仍然不为空。
这个问题属于有多线程的意识,但对AtomicBoolean
不明所以,用的糊里糊涂。工作中之前也曾遇到过相同的问题,把原本的boolean
直接替换成AtomicBoolean
,只使用get
, set
却不使用compareAndSet
。
修改后的代码:
1 | private static final AtomicBoolean sIsExecuting = new AtomicBoolean(false); |
顺便还修复了一个Timer
未反初始化的问题。这个问题会造成Timer线程不退出。这也是非常容易忽视的问题,原代码在任务完成后直接将sTimer
置空,而没有检查这时sTimer
是否有值。
Java的Timer很不好用,添加的任务无法取消,只能把Timer自己cancel了,然后这个Timer就不能用了,想用只能再new一个。还是Android的Handler方便。