1、Executor框架将任务的提交过程与执行过程解耦开来,并用Runnable来表示任务。

图画的不规范,全部用类来表示了。
其中Executor,ExecutorService和ScheduleExecutorService是接口,AbstractExecutorService是抽象类,Executors是工具类。
2、Executor基于生产者-消费者模式。如果要在程序中实现一个生产者-消费者的设计,最简单的方式通常就是使用Executor。
3、Executors提供了很多创建线程池的方法。
newFixedThreadPool:将创建一个固定长度的线程池,每当提交一个任务时就创建一个线程,直到到达线程池的最大数量,这时线程池的规模将不再变化。
newCachedThreadPool:创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求时,将回收空闲的线程,而当需求增加时,则可以添加新的线程,线程池的规模不存在任何限制。
newSingleThreadExecutor:是一个单线程的Executor,将创建单个线程来执行任务,如果线程异常结束,会创建另一个线程替代。任务是串行执行的。
newScheduledThreadPool:创建一个固定长度的线程池,以延时或定时的方式来执行任务,类似Timer。
4、JVM只有在所有(非守护)线程全部终止后才会退出,无法正确的关闭Executor,那么JVM将无法结束。
5、ExecutorService的生命周期有3种状态:运行,关闭和已终止。shutdown方法将执行平缓的关闭过程:不再接受新的任务,同时等待已经提交的任务执行完成,shutdownnow方法将执行粗暴的关闭过程:它将尝试取消所有运行中的任务,并且不再启动队列中尚未开始执行的任务。
6、考虑使用ScheduledThreadPoolExecutor来代替Timer。
7、完成服务(CompletionService)将Executor和BlockingQueue的功能融合在一起,将Callbable提交给它,使用take和poll等方法来获取已完成的结果。
8、可以设置取消标志来取消任务的执行,该标志必须为volatile类型,任务定期查看该标志,如果设置了这个标志,任务将提前结束。
9、Thread中包含了中断线程以及查询线程中断状态的方法,interrupt方法能中断目标线程,而isInterrupted方法能返回目标线程的中断状态,静态的interrupted方法可以清除当前线程的中断 状态。
10、对中断操作的正确理解是:它并不会真正地中断一个正在运行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己。通常,中断是实现取消的最合理方式。
11、当wait, sleep和join收到中断请求或者在开始执行时发现某个已被设置好的中断状态时,将抛出一个异常。
12、调用interrupt并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息。
13、不建议无限制的创建线程,因为线程生命周期的开销非常高,资源消耗严重,影响稳定性。
14、对于持有线程的服务,只要服务的存在时间大于创建线程的方法的存在时间,就应该提供生命周期方法。
15、当取消一个生产者 - 消费者操作时需要同时取消生产者和消费者。
16、ExecutorService的两种关闭方法:shutdown正常关闭,ExecutorService会一直等到队列中的所有任务都执行完成后才关闭,速度慢,更安全;shutdownNow强行关闭首先关闭当前正在执行的任务,然后返回所有尚未启动的任务清单,速度快,风险大。
17、另一种关闭生产者-消费者服务的方式就是使用毒丸对象:毒丸是指一个放在队列上的对象,其含义是:当得到这个对象时,立即停止。
18、关闭钩子是指通过Runtime.addShutdownHook注册的但尚未开始的线程。关闭钩子可以用于实现服务或应用程序的清理工作。
19、线程可分为两种:普通线程和守护线程。普通线程与守护线程之间的差异仅在于当线程退出时发生的操作。当JVM停止时,所有仍然存在的守护线程都将被抛弃,既不会执行finally代码块,也不会执行回卷栈,而JVM只是直接退出。
参考:
1、Java线程Thread.join方法解析
网友评论