Executor以及线程池

在应用程序中,老是会出现大量的任务,包括相同类型的和不一样类型的。要快速处理这些任务,常见方法就是利用多线程,可是也不可能为每一个任务都建立一个线程,这样内存也不够,而且线程的建立销毁开销很大。最好是少许线程处理大量任务,实现线程的复用,Executor干的就是这事。程序只须要把任务提交给Executor,由Executor来肯定怎么来执行这个任务,即执行策略。Executor的关闭很重要,若是Executor若是没有关闭,那JVM将没法结束。关闭方法有shutdown,shutdownNow,shutdown方法执行平缓关闭,若该任务没有提交则拒绝提交,若该任务已经提交可是没有执行,将等待它执行完成,若该任务已经执行将等待它执行完成。shutdownNow是粗暴关闭,取消如今执行的任务,拒绝处理新任务,再也不启动线程池队列中已提交的任务。当全部已经提交到Executor的任务都执行完成时,Executor将进入terminatede终止状态。网络

线程池的底层原理:数据结构:线程池管理器(ThreadpoolFactory),worker,任务队列Blockqueue;线程池的调度:新提交一个任务时,全部看下现有的线程数量是否是达到了corepoolSize,若是没有将新建一个线程thread,该线程将执行该任务,当该任务执行完成时,它会去任务队列中取出任务而后执行任务。若当前线程的数量大于corepoolSize小于maxpoolSize,则看下任务队列是否已经满了,若满了则新建线程thread,若没有满则将任务丢到任务队列中。数据结构

任务的取消和关闭多线程

建设一个任务执行到一半,程序想取消这个任务,那怎么办呢?最好的方法是由每一个任务本身来决定如何取消本身,这将保持数据的一致性,不会乱。常见的方法是轮询一个取消标志位,当该标志位被设立了,则执行本身的取消策略。这种方式会有个弊端,当执行该任务的线程因为某种缘由被阻塞掉,那它将看不到标志位的设立,这个时候将加入中断Interrupted。当调用Thread.interrupted()时,线程的中断标志位会被设立,阻塞方法会检查中断标志位,将发现中断标志位为true时,将结束阻塞,重置中断位,提早返回并抛出中断异常。中断处理策略:抛出异常(我不想管了,谁爱管谁管),捕获异常(管了就不能无做为),恢复中断位(我想管,我告诉别人我是要中断的)。说了这么多如何管理任务的生命周期,最后发现Future已经提供了任务的周期的管理抽象,尴尬。对于不可中断的阻塞方法(同步io,Selector.select()方法,获取内置锁)经过中断不能达到取消任务的效果,只能特殊处理,好比说关闭socket.close(),抛出中断异常。当一个线程执行任务时,任务抛出一个未受检异常。jvm将捕获到异常,并终止线程,可是对于Executor这样的服务来讲,终止一个线程可能会使它产生影响,因此它捕获异常并新增一条工做者线程(具体是新增仍是无论看当前的线程数)。虽然这看起来好像没什么问题,可是这对于程序来讲却显的莫名其妙,一个任务无声无息就取消了。针对这种状况提供了一个UncaughtExceptionHandler异常捕获器,线程池能够为每一个线程配一个异常捕获器(经过线程池管理器实现)。jvm

线程池的使用socket

任务的种类比较复杂,为了更好的利用线程池的优点,对于线程池须要显示配置,选择Executors.newFixThreadpool,Executors.newCacheThreadpool,Executors.newSingleThreadpool,Executors.newScheduleThreadExecutor建立不一样的线程池。选择哪一种线程池:singleThreadpool线程池能够更好的同步,当多个任务同时操做一个资源,即便该资源不是同步的,使用singleThreadpool线程池能保证当前任务对状态的修改能对下一个任务可见。FixThreadpool用于限制任务的数量以保证资源过程问题(网络操做常见),cacheThreadpool适用于长时间任务和短期任务并行的场景,依赖性任务(会出现线程饥饿)。线程池大小的选择,计算型密集的任务选择跟cpu数,IO密集型的根据公式计算(偷个懒,不写了)。任务队列的选择:有界队列,无界队列,sychronizedQueue,priorityBlockingQueue。饱和策略的选择:停止,抛弃,discardOldestPolicy,调用者运行。线程

相关文章
相关标签/搜索