三叶草 发表于 2021-12-26 16:48:46

项目创建了几百个线程,你要怎么优化?,安卓View Handler Binder

(any?as?Runnable).run()
//?任务已执行结束,callStack表示task添加栈,此时应为空代表线程当前无任务在运行
info.callStack?=?""
}
override?fun?call():?Any?{
//?类似run()方法
}
override?fun?compareTo(other:?Any):?Int?{
//?省略代码
}
}
这里有一点要说明,有些task可能同时继承于Runnable、Callable、甚至Comparable,如果只包装成Runnable,当调用其他接口方法时会crash,所以这里要把已知的可能会继承的接口都实现。(当然如果后面发现没覆盖全,可以把新的接口继续加进来。至于用户自定义Runnable实现很多接口的情况不用担心。因为替换为PoolRunnable后都是系统代码在运行,主要看系统代码是否会调用call()、compareTo()等方法就好,上层随意调用被包装的runnable中各种自定义方法是没问题的)。
但是对于建立“线程-线程池”关系来说,这样要等到run()方法被执行时才能建立关系,感觉有点晚。这里可以更进一步,替换掉线程池中threadFactory,同样是自己包一层,在newThread()方法中即可及时拿到线程池创建的线程,这样就可以先和线程池建立关联,然后run()时再和堆栈建立关联。好了!new方式创建的线程池搞定,接下来看看Executors.xxx怎么玩,我们可不可以自己写个ProxyExecutors,使用asm把所有Executors.xxx都替换成ProxyExecutors.xxx,然后把其中new ThreadPool都换成new BaseThreadPool呢?
object?ProxyExecutors?{
@JvmStatic
fun?newFixedThreadPool(nThreads:?Int):?ExecutorService?{
return?BaseThreadPoolExecutor(
nThreads,?nThreads,
0L,?TimeUnit.MILLISECONDS,
LinkedBlockingQueue()
)
}
@JvmStatic
fun?newCachedThreadPool():?ExecutorService?{
return?BaseThreadPoolExecutor(
0,?Int.MAX_VALUE,
60L,?TimeUnit.SECONDS,
SynchronousQueue()
)
}
@JvmStatic
fun?newScheduledThreadPool(
corePoolSize:?Int,
threadFactory:?ThreadFactory?
):?ScheduledExecutorService?{
return?BaseScheduledThreadPoolExecutor(corePoolSize,?threadFactory)
}
}
对于某些线程池确实没啥问题,但当你继续写下去时,会出问题,比如:
@JvmStatic
fun?newSingleThreadScheduledExecutor():?ScheduledExecutorService?{
return?BaseDelegatedScheduledExecutorService(
ScheduledThreadPoolExecutor(1)
)
}
DelegatedScheduledExecutorService是Executors的私有内部类,没办法方便的写出BaseDelegatedScheduledExecutorService。所以继续观察下,发现所有创建线程池方法都返回的都是ExecutorService或ScheduledExecutorService,既然这么统一,并且这两个都是接口,那我们就使用动态代理吧!通过代理,就可以拿到接口的各种方法以及方法参数,然后为所欲为。以ExecutorService接口为例:
object?ProxyExecutors?{
@JvmStatic
fun?newFixedThreadPool(nThreads:?Int):?ExecutorService?{
return?proxy(Executors.newFixedThreadPool(nThreads))
}
}
private?fun?proxy(executorService:?ExecutorService):?ExecutorService?{
if?(executorService?is?ThreadPoolExecutor)?{
//?这里和BaseThreadPoolExecutor一样,设置ThreadFactory为了尽早获取线程信息和线程池建立联系,而不用等到run时
executorService.threadFactory?=?BaseThreadFactory(
executorService.threadFactory,
toObjectString(executorService)
)
}
val?handler?=?ProxyExecutorService(executorService)
return?Proxy.newProxyInstance(
executorService.javaClass.classLoader,
AbstractExecutorService::class.java.interfaces,
handler
)?as?ExecutorService
}
//?这里使用java是因为kotlin在调用java变长参数方法时有坑
public?class?ProxyExecutorService?implements?InvocationHandler?{
private?ExecutorService?executor;
private?String?poolName?=?null;
ProxyExecutorService(ExecutorService?executor)?{
this.executor?=?executor;
poolName?=?TrackerUtils.toObjectString(executor);
//?初始化时获取线程池信息
String?createStack?=?TrackerUtils.getStackString(false);
//?省略部分代码
}
@Override
public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
//?因方法数众多,并且被代理的各类中方法也不一致
//?所以被调用方法中只要含有Runnable、Callable类型的参数,都替换成PoolRunnable代理
if?(args?!=?null)?{
String?callStack?=?TrackerUtils.getStackString(true);
for?(int?i?=?0;?i?<?args.length;?i++)?{
Object?arg?=?args;
if?((arg?instanceof?Runnable?||?arg?instanceof?Callable)?&&?!(arg?instanceof?PoolRunnable))?{
//?execute?submit?等情况
PoolRunnable?any?=?new?PoolRunnable(arg,?callStack,?poolName);
//?替换方法参数
args?=?any;
}?else?if?(arg?instanceof?Collection?&&?!((Collection)?arg).isEmpty())?{
//?invokeAny?invokeAll?等情况
Iterator?iter?=?((Collection)?arg).iterator();
ArrayList<PoolRunnable>?taskList?=?new?ArrayList<>();
boolean?allOk?=?iter.hasNext();
while?(iter.hasNext())?{
Object?it?=?iter.next();
if?(it?instanceof?Runnable?||?it?instanceof?Callable)?{
if?(it?instanceof?PoolRunnable)?{
taskList.add((PoolRunnable)?it);
}?else?{
taskList.add(new?PoolRunnable(it,?callStack,?poolName));
}
}?else?{
allOk?=?false;
break;
}
}
if?(allOk)?{
//?替换方法参数
args?=?taskList;
}
}
}
}
if?(method.getName().equals("shutdown")?||?method.getName().equals("shutdownNow"))?{
ThreadInfoManager.getINSTANCE().shutDownPool(poolName);
}
return?method.invoke(executor,?args);
}
}
在invoke方法中,我们把所有参数为Runnable或Callable的都替换成自己的PoolRunnable,后面和new创建线程池的套路一样,在PoolRunnable的run()或call()方法中进行线程与堆栈的关联。完美!但是考虑一个问题,如果有人不幸写出这样的代码,会发生什么呢?
val?pool?=?Executors.newFixedThreadPool(3)?as?ThreadPoolExecutor

最后
总而言之,Android开发行业变化太快,作为技术人员就要保持终生学习的态度,让学习力成为核心竞争力,所谓“活到老学到老”只有不断的学习,不断的提升自己,才能跟紧行业的步伐,才能不被时代所淘汰。
在这里我分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。需要的朋友可以私信我【资料】或者 点这里 免费领取



还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。 领取地址: Android学习PDF+架构视频+最新面试文档+源码笔记


https://blog.51cto.com/u_15465267/4845395
页: [1]
查看完整版本: 项目创建了几百个线程,你要怎么优化?,安卓View Handler Binder