前言
本插件内容是结合多家博客的精华改造而成的
插件地址:github.com/heyan224/la...
该插件主要是基于github.com/Knight-ZXW/... 的基础上细化改造的
目标
线程优化就是将自己代码中的线程以及各种sdk 中创建的线程都收敛到统一的线程池中,方便线程的管理。
我们知道创建线程的方式有多种:
new Thread
new ScheduledThreadPoolExecutor
new ThreadPoolExecutor
new FixedThreadPool
new CachedThreadPool
Executors.newSingleThreadExecutor()
new HandlerThread
随着业务的膨胀以及接入各种三方sdk越来越多,那么在我们的apk中将存在大量无法管控的Thread
实例以及 ThreadPoolExecutor
实例。
所以要达到线程收敛的目的就是要将 各种 new Thread
以及new ThreadPoolExecutor
等等实例都变成 一个 ,比如new ProxyThread
、new PThreadPoolExecutor
以某一个sdk为例,线程收敛前某sdk的现状如下:
优化后:
我们已经将sdk中new Thread
以及new ThreadPoolExecutor
相关代码都改了
问题来了,即使都改成了new ProxyThread
、new PThreadPoolExecutor
,这不是依然有很多线程和线程池的实例吗,依然没有达到收敛的目的?
确实,要想达到收敛的目的,还需要做一些事情,拿PThreadPoolExecutor
为例
我们在PThreadPoolExecutor
重写了ThreadPoolExecutor
中的 execute
方法和 submit
方法,当有人向线程池中提交任务时,我们这里并没有开启线程,而是通过 DefaultThreadPoolExecutor.
getHCoreThreadPool
().execute(command)
将任务丢到了新的线程池中。 所以可以看出PThreadPoolExecutor
并不是真正的线程池,真正的线程池是 getHCoreThreadPool()
,它是一个单例。
kotlin
public class PThreadPoolExecutor extends ThreadPoolExecutor {
//..........
//.........
@Override
public void execute(Runnable command) {
if (!SuperThreadPoolManager.isProxyThreadEnable()) {
super.execute(command);
return;
}
try {
DefaultThreadPoolExecutor.getHCoreThreadPool().execute(command);
} catch (OutOfMemoryError error) {
DefaultThreadPoolExecutor.getExtraThreadPool().execute(command);
}
}
@Override
public Future<?> submit(Runnable task) {
if (!SuperThreadPoolManager.isProxyThreadEnable()) {
return super.submit(task);
}
try {
return DefaultThreadPoolExecutor.getHCoreThreadPool().submit(task);
} catch (OutOfMemoryError error) {
return DefaultThreadPoolExecutor.getExtraThreadPool().submit(task);
}
}
@Override
public <T> Future<T> submit(Callable<T> task) {
if (!SuperThreadPoolManager.isProxyThreadEnable()) {
return super.submit(task);
}
try {
return DefaultThreadPoolExecutor.getHCoreThreadPool().submit(task);
} catch (OutOfMemoryError error) {
return DefaultThreadPoolExecutor.getExtraThreadPool().submit(task);
}
}
}
使用
- 项目的根目录下的
build.gradle
中添加
classpath 'io.github.heyan224:lancet-plugin:0.0.6'
- app目录下的
build.gradle
中添加
implementation 'io.github.heyan224:lancet-runtime:0.0.2'
- 还是在 app目录下的
build.gradle
中添加如下的配置
bash
apply plugin: 'LancetX'
LancetX{
enable true
enableInDebug true
weaveGroup {
threadOptimize {
enable false
whiteNames = [
"com/bb",
"com/aa",
"com/xx"
]
blackNames = [
]
}
}
}
这里解释几个关键的字段:
arduino
threadOptimize { // 线程优化配置项
enable true // 开关
whiteNames = [ // 白名单,我们可以添加白名单,来指定特定的几个sdk来进行线程优化
"com/bb",
"com/aa",
"com/xx"
]
blackNames = [ // 黑名单
]
}
- 最后一步就是来实现 我们自己的
ProxyThread
PThreadPoolExecutor
代码了,以及Thread
和ProxyThread
的映射,ThreadPoolExecutor
和PThreadPoolExecutor
的映射
也就是我们要告诉字节码修改插件,我们想要修改哪些类,比如我们将要修改 Thread
类,修改为 ProxyThread
,代码如下图。
另外 ProxyThread
、PThreadPoolExecutor
、getHCoreThreadPool()
的实现都已在仓库中了
注意点
线程收敛到这里其实还没开始,因为真正重要的是我们的代理线程池的参数应该如何配置。
我们都知道线程池有几个重要的参数需要深思熟虑
- 线程池核心线程数
- 线程池最大线程数
- 任务等待队列
- 线程空闲多久要回收,也就是keepAliveTime
- 线程任务拒绝策略的制定 RejectedExecutionHandler
这几个参数的制定对于线程收敛很重要。