一天,同事抛给我一个线上崩溃。堆栈如下(复现的代码)
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方便。