赞
踩
还在手写循环线程?就用他(ScheduledExecutorService),优雅点!
优点:
最大优点除了线程池的特性以外,可以实现循环或延迟任务。
下面部分内容引用该博客:ScheduledExecutorService的使用
引用博客内容 |
---|
ScheduledExecutorService 和 Timer 的区别
Timer的内部只有一个线程,如果有多个任务的话就会顺序执行,这样我们的延迟时间和循环时间就会出现问题。
ScheduledExecutorService是线程池,所以就不会出现这个情况,在对延迟任务和循环任务要求严格的时候,就需要考虑使用ScheduledExecutorService了。
ScheduledExecutorService的用法主要有三个:
public class MainActivity extends AppCompatActivity { // 通过静态方法创建ScheduledExecutorService的实例 private ScheduledExecutorService mScheduledExecutorService = Executors.newScheduledThreadPool(4); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 延时任务 mScheduledExecutorService.schedule(threadFactory.newThread(new Runnable() { @Override public void run() { Log.e("lzp", "first task"); } }), 1, TimeUnit.SECONDS); // 循环任务,按照上一次任务的发起时间计算下一次任务的开始时间 mScheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { Log.e("lzp", "first:" + System.currentTimeMillis() / 1000); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }, 1, 1, TimeUnit.SECONDS); // 循环任务,以上一次任务的结束时间计算下一次任务的开始时间 mScheduledExecutorService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { Log.e("lzp", "scheduleWithFixedDelay:" + System.currentTimeMillis() / 1000); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }, 1, 1, TimeUnit.SECONDS); } }
在代码中已经有注释说明这三个方法的用法,重点是scheduleAtFixedRate和scheduleWithFixedDelay的区别,下面看具体看一下Log信息:
首先是scheduleAtFixedRate:
这里写图片描述
从log上看,我们的循环任务严格按照每一秒发起一次,sleep(3000)对于任务的开启是没有影响的,也就是以上一个任务的开始时间 + 延迟时间 = 下一个任务的开始时间。
然后是scheduleWithFixedDelay:
这里写图片描述
从log上看,每一个任务的时间间隔是4秒,而不是我们设置的间隔1秒,任务要耗时3秒,两个时间相加正好是4秒,那么之前代码注释的解释就说的通了:以上一次任务的结束时间 + 延迟时间 = 下一次任务的开始时间。
扩展:ThreadFactory
因为在线程池的构造方法中,有ThreadFactory参数,所以就来简单介绍一个ThreadFactory:
线程工厂,可以对传入的Runnable进行加工操作,典型的工厂模式,需要实现newThread(@NonNull Runnable r) 方法返回加工后的线程。
看一下具体的代码:
private ThreadFactory threadFactory = new ThreadFactory() {
@Override
public Thread newThread(@NonNull final Runnable r) {
return new Thread() {
@Override
public void run() {
r.run();
Log.e("lzp", "嘿嘿嘿");
}
};
}
};
例如上面的代码,我在参数Runnable对象的run方法后,增加了一句log打印。
然后修改MainActivity的调用:
mScheduledExecutorService.schedule(threadFactory.newThread(new Runnable() {
@Override
public void run() {
Log.e("lzp", "first task");
}
}), 1, TimeUnit.SECONDS);
这里面我传入ThreadFactory加工过后的Runnable,我们推断,最后应该会打印两句:first task 和 嘿嘿嘿,运行一下看看是不是符合我们的期望:
这里写图片描述
果然结果没有让我们失望。
然后我有了一个想法,我要给线程池所有的线程都加工一下:
private ScheduledExecutorService mScheduledExecutorService = Executors.newScheduledThreadPool(4, new ThreadFactory() {
@Override
public Thread newThread(@NonNull Runnable r) {
return new Thread(r){
@Override
public void run() {
Log.e("lzp", "newThread");
super.run();
Log.e("lzp", "newThread over");
}
};
}
});
我在Runnable参数的run方法前后增加了打印,于是我迫不及待的运行了app:
这里写图片描述
经过短暂的喜悦,我发现我的希望落空了,出现了两个问题:
1、Log.e(“lzp”, “newThread over”) 这一句为什么没有执行???
2、为什么ThreadFactory.newThread() 只执行了四次。
带着疑问我开始查看源码,经过仔细的思考,找到了问题的原因,这里就简单解释一下:
1、线程池只会创建最大并发数(corePoolSize)的Worker对象。
2、Worker对象内部包含了Thread和Runnable信息。
3、添加任务时:
如果Worker没有到最大值,就创建Worker(通过ThreadFactory的newThread新建了Thread,所以Thread的数量等于Worker数量);
如果已经是最大,就把任务放到队列(Quene)中。
3、任务执行中:
如果Worker的Runnable不为空,执行Runnable,执行结束,Runnable设置为空;
如果Worker的Runnable为空,从队列中取出任务执行。
4、Runnable运行结束,线程池内部直接退出了线程。
弄懂了内部的机制,刚才的问题就全都弄明白了,还发现android的设计者是不希望我们通过这种方法去影响Runnable的实现方法,但是可以去改变线程Thread对象的属性,例如优先级等等。
总结
这一篇我们先去弄懂了ScheduledExecutorService的特性和用法,然后了解了ThreadFactory的用法,最后两者结合使用,分析并解决可能出现的问题。
由于线程池的源码还是很多的,这里就不具体的解释了,想具体了解的朋友可以自己去查看源码或者网上查看资料。
最后带上源码链接,有问题或者建议可以留言。
引用博客内容–结束 |
---|
static {
ScheduledExecutorService pruneTimer = new ScheduledThreadPoolExecutor(1, r -> new Thread(r, "prune-cache-timer-"));
pruneTimer.scheduleWithFixedDelay(() -> {
LOG.warn("prune cache now----- ");
}, 1, 1, TimeUnit.HOURS);
}
scheduleAtFixedRate 与 scheduleWithFixedDelay 的区别:
scheduleAtFixedRate ,是以上一个任务开始的时间计时,N秒过去后,检测上一个任务是否执行完毕,如果上一个任务执行完毕,则当前任务立即执行,如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行。
scheduleWithFixedDelay,是以上一个任务结束时开始计时,N秒过去后,立即执行。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。