合理使用线程池能带来如下几点好处:
1、降低资源的消耗
通过重复利用已经创建的线程降低线程创建和销毁造成的消耗
2、提高响应速度
当任务到达时,任务可以不需要等到线程创建就能立即执行
3、提高线程的可管理性
线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统稳定性,使用线程池可以进行 统一分配,调优和监控
线程池将自动调整池的大小根据corePoolSize和maximumPoolSize;当一个新任务被提交执行后,
若线程池中工作线程数小于corePoolSize时,一个新的线程将会创建并处理当前的请求,即使有其他空闲的线程;若工作线程数多于corePoolSize,但是少于maximumPoolSize时,只有当队列满时新的线程才会创建,通过设置corePoolSize和maximumPoolSize相等即可创建一个固定大小的线程池
如果当前线程池中有多于corePoolSize的工作线程,若超出线程一直闲置超过keepAliveTime时间时,那么它们就将被终止,故当线程池中的工作线程没有积极使用时,减少资源消耗;如果线程池更加活跃时,新的工作线程将会被创建
任何BlockingQueue可能用来传递和保持提交的任务,该队列使用线程池大小相互影响,若线程池中工作线程数小于corePoolSize时,线程池总是先创建一个新的工作线程,而不是排列,目前提供3种queue策略:SynchronousQueue、LinkedBlockingQueue、ArrayBlockingQueue
当线程池已经关闭(采用有限范围的最大线程和工作队列容量并饱和),一个新的任务被提交执行时,那么该任务将被Rejected,在这情况下,线程池将调用饱和处理,提供饱和处理策略:AbortPolicy、CallerRunsPolicy、DiscardPolicy、DiscardOldestPolicy
线程池合理配置
根据任务特性分析如下:
1、任务性质:CPU密集型,IO密集型和混合型
2、任务优先级:高和低
3、任务执行时间:长和短
4、任务依赖性:是否依赖其他资源,如数据库连接
CPU密集型的任务尽可能小的线程,如N+1个线程(N为CPU的个数);IO密集型由于线程并不是一直在执行任务,则尽可能多的配置线程,如2×N;混合型任务,如果可以拆分,则将其拆分成一个CPU密集型任务和一个IO密集型任务,只要时间相差不大;优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理;依赖数据库连接池的任务,因为线程提交sql后需要等待数据库返回结果,如果等待时间越长,CPU空闲时间就越长,那么线程数就应该设置越大,才能更好利用CPU
public class PausableThreadPoolExecutor extends ThreadPoolExecutor { private boolean isPaused; private ReentrantLock pausedLock = new ReentrantLock(); private Condition unpaused = pausedLock.newCondition(); public PausableThreadPoolExecutor() { super(2, 4, 500, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1)); } @Override protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); pausedLock.lock(); try { while (isPaused) unpaused.await(); } catch (InterruptedException e) { t.interrupt(); } finally { pausedLock.unlock(); } } public void pause() { pausedLock.lock(); try { isPaused = true; } finally { pausedLock.unlock(); } } public void resume() { pausedLock.lock(); try { isPaused = false; unpaused.signalAll(); } finally { pausedLock.unlock(); } } }