标签:factor lan shutdown 需求 操作 策略 元素 线程 表示
参考博文:http://blog.csdn.net/mark_lq/article/details/50346999
合理利用线程池能够带来三个好处。
1.降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗
2.提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行
3.提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控
Executor线程池框架最大优点是把任务的提交和执行解耦。呵护短将要执行的任务封装成Task,然后提交即可。具体来说,提交一个Callable对象给ExecutorService(如最常用的线程池ThreadPoolExecutor),将得到一个Future对象,调用Future对象的get方法等待执行结果
下图是线程池所涉及到的所有类的结构图,先从整体把握下
??????????????图1 线程池实现原理类结构图
??上面这个图是很复杂的,涉及到了线程池内部实现原理的所有类,不利于我们理解线程池如何使用。我们先从客户端的角度出发,看看客户端使用线程池所涉及到的类结构图:
??????????????图2 线程池使用的基本类结构图
??从图一可知,实际的线程池类是实现ExecutorService接口的类,有ThreadPoolExecutor、ForkJoinPool和ScheduledThreadPoolExecutor。下面以常用的ThreadPoolExecutor为例讲解。
1 public ThreadPoolExecutor(int corePoolSize, 2 int maximumPoolSize, 3 long keepAliveTime, 4 TimeUnit unit, 5 BlockingQueue<Runnable> workQueue, 6 ThreadFactory threadFactory, 7 RejectedExecutionHandler handler)
注:当我们创建一个线程池的时候,并不会直接就创建出相应数量的线程
而是,只有当提交一个任务到线程池时,在当前线程数小于线程池的基本线程数数线程池时,会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程
如果调用了线程池的 prestarAllCoreThreads方法,线程池会提前创建并启动所有基本线程
参数说明:
1.corePoolSize (线程池的基本线程数)如:Executors.newFixedThreadPool(5),它的基本线程数就是5
2.maxinumPoolSize (线程池最大线程数)线程池允许创建的最大线程数。如果任务队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果
注:一般默认创建线程池的的时候,maxinumPoolSize = corePoolSize ,即任务队列满了的话,就直接拒绝了,不会创建线程
关于任务队列,我们后面会再详解介绍
3.keepAliveTime(线程活动保持时间) 这个参数表示,线程池的工作线程在空闲状态下,存活的时间。(默认为0,即线程闲下来就将其释放)所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率
4.TimeUnit (线程活动保持时间的单位),这个参数是为前面那个参数服务的,默认为 毫秒
5.workQueue(任务队列) 用于保存等待执行的任务的阻塞队列,当线程池中线程执行任务执行不过来的时候,会将等待执行的任务放到这个队列中,可以选择以下几个阻塞队列
JDK中默认选用LinkedBlockingQueue作为阻塞队列的原因就在于其无界性。因为线程大小固定的线程池,其线程的数量是不具备伸缩性的,当任务非常繁忙的时候,就势必会导致所有的线程都处于工作状态,如果使用一个有界的阻塞队列来进行处理,那么就非常有可能很快导致队列满的情况发生,从而导致任务无法提交而抛出RejectedExecutionException,而使用无界队列由于其良好的存储容量的伸缩性,可以很好的去缓冲任务繁忙情况下场景,即使任务非常多,也可以进行动态扩容,当任务被处理完成之后,队列中的节点也会被随之被GC回收,非常灵活。
7.RejectExecutionHandler(拒绝策略):当队列和线程池都满了,什么时候会出现这种情况呢?应该是要满足: (任务队列选用的是有界的队列,任务队列满已时,且当前线程数也已经达到了线程池的最大线程数maxinumPoolSize )
那么就必须要采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出的异常。以下是JDK1.5提供的四种策略
AbortPolicy:直接抛出异常
CallerRunsPolicy:只用调用者所在线程来运行任务
DiscardOldestPolicy:丢弃队列里最后一个要执行任务,并执行当前任务
DiscardPolicy:不处理,直接丢弃
当然也可以根据应用场景来实现RejectedExecutionHandler接口自定义拒绝策略,如记录到日志或持久化不能处理的任务
由此可见,创建一个线程所需的参数非常多,线程池为我们提供了类Executors的静态工厂方法用来创建不用类型的线程池,官方也建议我们使用它,它会给上面的参数给上一些默认值
当然我们也可以自己创建线程池,自由地给定参数,来更好的适应不同的场景
b)向线程池提交任务
有两种方式提交任务(execute 和 submit)两者执行任务最后都会通过Executor的execute方法来执行,关于 execute方法,我们后面会详解,
两者区别:1.异常处理,两者对待run方法抛出的异常处理方式不一样
2.有无返回值,submit有返回值,而execute没有
具体怎么用,可以参考上一篇文章,
c)线程池关闭
1.shutdown()方法
这个方法会平滑地关闭ExecutorService,当我们调用这个方法时,ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务分两类:一类是已经在执行的,另一类是没有开始执行的),当所有已经提交的任务执行完毕后将会关闭 ExecutorService
2.awaitTermination(long timeout,TimeUnit unit)方法
这个方法有两个参数,一个是timeout即超时时间,另一个是unit即时间单位。这个方法会使当前关闭线程池的线程 等待 timeout时长,当超过timeout时间后,则去监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。一般情况下会和shutdown方法组合使用
3.shutdownNow()方法:这个方法会强制关闭ExecutorService,它将取消所有运行中的任务和在工作队列中等待的任务,这个方法返回一个List列表,列表中返回的是等待在工作队列中任务
前面提到ExecutorService的submit方法 和 execute方法都会调用Executor实现类(如ThreadPoolExecutor)的execute方法,下面我们来看看任务提交到这个方法是如何执行的,从这个方法入手分析 线程池的执行流程
源码 谷歌翻译
标签:factor lan shutdown 需求 操作 策略 元素 线程 表示
原文地址:http://www.cnblogs.com/xuzekun/p/7491958.html