常见坑
SimpleDateFormat是线程不安全对象
推荐使用线程安全的format,apache、joda-time等工具包均有实现
Timer
当一个Timer运行多个TimerTask时,只要其中一个TimerTask在执行中向run方法外抛出了异常,则其他任务也会自动终止。
日常开发中使用定时器功能时应该优先使用ScheduledThreadPoolExecutor。
创建线程和线程池时要指定与业务相关的名称
方便快速定位问题
FutureTask
线程池使用 FutureTask 时如果把拒绝策略设置为DiscardPolicy和DiscardOldestPolicy,并且在被拒绝的任务的 FutureTask 对象上调用了无参get方法,那么调用线程会一直被阻塞。
当使用FutureTask时,尽量使用带超时时间的get方法,这样即使使用了DiscardPolicy拒绝策略也不至于一直等待,超时时间到了就会自动返回。如果非要使用不带参数的get方法则可以重写DiscardPolicy的拒绝策略,在执行策略时设置该Future的状态大于COMPLETING即可。
使用 Thread Local 不当可能会导致内存泄漏
当一个线程调用 ThreadLocal 的set方法设置变量时,当前线程的 ThreadLocalMap里就会存放一个记录,这个记录的key为 ThreadLocal 的弱引用, value则为设置的值。如果当前线程一直存在且没有调用 ThreadLocal 的 remove方法,并且这时候在其他地方还有对 ThreadLocal 的引用,则当前线程的 ThreadLocalMap 变量里面会存在对 ThreadLocal 变量的引用和对 value对象的引用,它们是不会被释放的,这就会造成内存泄漏。
线上问题定位
在Lmⅸ命合行下使用TOP命查看每个进程的情况
再使用top的交互命令数字1查看每个CPU的性能数据。(如果
这里显示CPU利用率100%,则很有可能程序里写了一个死循环。)使用top的交互命令H查看每个线程的性能信息。
- 某个线程CPU利用率一直100%,则说明是这个线程有可能有死循环,那么请记住这个PID。(也可能是Full GC造成,jstat查看GC情况)
- 某个线程一直在TOP10的位置,这说明这个线程可能有性能问题
- CPU利用率高的几个线程在不停变化,说明并不是由某一个线程导致CPU偏高。
jstack dump线程信息,看下是哪个线程、执行哪一行代码造成CPU利用率高。
dump出来的线程ID(nid)是十六进制的,而我们用TOP命命看到的线程ID是十进制的,所以要用 printf "%x\n" num 转换一下进制。然后用十六进制的ID去dump里找到对应的线程。