目录
前言:
文章,一为温故而知新,二若是可以帮助到别人,也是我的荣幸。
因本人能力有限,若有错误之处,麻烦指出。如果觉得有可取之处,麻烦点赞支持一下。 😊
1.方向
线程该怎么去优化?有那些线程该优化?最终我又该呈现什么样指标给组长看?
在做这件事之前,我脑海里面有过这些思考。既然有了问题,那么就有了大概方向,先解决自己心中的这些疑问,再去着手优化。
线程该怎么去优化?有那些线程该优化?
这个问题其实又可以这么说,线程在使用过程中,有那些问题,应该注意些什么事项。
理论知识如下:
1.线程的创建和销毁都需要时间,当有大量的线程创建和销毁时,那么这些时间的消耗则比较明显,将导致性能上的缺失
2.大量的线程创建、执行和销毁是非常耗 cpu 和内存的,这样将直接影响系统的吞吐量,导致性能急剧下降,如果内存资源占用的比较多,还很可能造成 OOM
3.大量的线程的创建和销毁很容易导致 GC 频繁的执行,从而发生内存抖动现象,而发生了内存抖动,对于移动端来说,最大的影响就是造成界面卡顿
实际中发现的问题:
1.有些线程,你压根都不知道是从哪里来的,没有名称,想优化它,都找不到来源。(当然最后使用profile找到了线程来源)
2.到处都是线程池,最可恶的是,线程池的参数还用错了线程池参数的使用
3.多余的线程切换,明明都已经是子线程了,还要再切一次到子线程执行
4.随处可见的new Thread
基于以上的理论和实际情况,我确定了3个优化方向。
优化方向
1.确定线程来源,去除无效线程和没必要的线程切换
2.将野生线程(new Thread之类的随手创建的线程)归并入线程池
3.整合线程池,明确各个线程池的使用场景
该呈现什么的指标?
1.把线程的来源给标注,也就是告诉领导这些线程是必须的,没得优化了
2.降低峰值线程数,减少平稳状态下的最大线程数
2.具体实施
第一步:确定线程来源
线程来源的确定据我了解是两种方式。
1.hook线程的构造函数,然后通过打印确定来源。(弱弱说一句,这个我没试过,但是很多文章都这么说了)
2.通过profile查看线程的堆栈信息,大致可以推测出线程的来源。
其实如果标注了名字的线程,都很好找,全局搜索就可以。不过,我遇到的有一种情况是有些是Maven库里面的,还要下载源码去确定。
profile的使用
如果在使用profile的过程,没办法识别到自己的进程,可以先确定一下自己使用的是不是debug版本。然后由于,我使用的是adb连接,有时候有些网络也没办法识别到,最后实在不行的话,尝试重启电脑,重启设备。
我目前使用的as是4.1版本
上图点击cpu,你就可以在左边看见当前进程中的线程了(如下所示)。
选择Trace Java Methods,接着点击record,然后对应用进行操作,再停止记录,就可以知道这段时间有那些线程在运行,又运行了那些代码,然后由此可以确定线程来源。
从上图可以看出imageloader-2是来于图片加载框架的。根据这个方法,可以确定大部分线程的来源。ps:有些是莫名其妙的第三方库的线程,这种就很难确认来源了。
第二步:去掉野生线程和没必要的线程切换
去掉野生线程比较好操作,直接全局搜有那些地方使用new Thread就可以,然后根据使用场景或者业务逻辑对其进行优化就好。
去掉没必要的线程切换的话,这个就需要自己对代码的熟悉程度了,这个比较耗精力,只能自己大概过一下代码,如果有啥的办法,麻烦告诉我。
第三步:整合线程池,划分线程池的使用场景
在我这个项目里面,使用线程的情况很多,毕竟七八年的老项目了,一直在迭代,里面的业务很复杂。综合考虑的话,使用了两个线程池,一个轻量级的线程池,一个重量级的线程池,轻量级线程池处理需要迅速反馈到UI的数据,重量级的线程池处理那些耗时比较长的任务。
具体怎么实施的,如果感兴趣的话,可以看一下。这篇文章的第三个问题
3.尾记
给我的感觉是,优化,其实很多时候都是处理别人留下来的代码问题,比如上文中乱开线程和线程池、没必要的线程切换等。完成功能从来都不是程序员唯一的任务,优秀的代码质量更能凸显出一个人的品质。
程序员何苦为难程序员,保持优秀的代码质量吧。
ps:设置线程的优先级和自己开发第三库时给别人提供注入线程池的接口也蛮重要的。
其实去年就有打算记录下来的心思,一下子拖了这么久。