使用执行器框架(Executor Framework)的第一步就是创建ThreadPoolExecutor对象。可以使用ThreadPoolExecutor类提供的四个构造器或者使用Executors工厂类来创建ThreadPoolExecutor对象,鉴于这些构造器在使用上的复杂性,推荐使用Executors工厂类来创建,一旦有了执行器就可以将Runnable或者Callable对象发送给它去执行了。
ThreadPoolExecutor是一个一个 ExecutorService,它使用可能的几个池线程之一执行每个提交的任务,通常使用 Executors 工厂方法配置。
线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。
使用较为方便的 Executors 工厂方法构建服务:
1. Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)
2. Executors.newFixedThreadPool(int)(固定大小线程池)
3. Executors.newSingleThreadExecutor()(单个后台线程),它们均为大多数使用场景预定义了设置。
最后要记得使用shutdown() 来关闭执行器,如果不关闭,则一直等待新任务的到来
简单的示例示例
场景描述:以下示例就是演示了,把一组线程交给执行器执行,在执行器中打印执行器中线程池中的一些任务信息。
结果说明
仔细看上面的线程名称,和task名称,可以看出来,3个任务只使用了2个线程。如果在更多的任务中,线程得到了复用。性能更好了 。
纵然线程重用减少了创建新线程所花费的时间,但缓存线程池也有缺点,因为新任务固定会依赖线程来执行,如果发送过多的任务给执行器,系统的负荷将会过载。尽当线程的数量是合理的或者线程只会运行很短的时间,适合采用Executors工厂类的newCachedThreadPool()方法来创建执行器。一旦创建了执行器就可以使用execute()方法来执行Runnable或Callable类型的任务。
上述例子中使用的方法:
getPoolSize():返回执行器线程池中实际的线程数。
getActiveCount():返回执行器中正在执行任务的线程数。
getCompletedTaskCount():返回执行器已经完成的任务数。
除了上述的newCachedThreadPool()外,还可创建固定大小的线程执行器,使用
这个执行器有一个线程数的最大值,如果发送超过这个最大值的任务给执行器,执行器将不再创建额外的线程,剩下的任务将被阻塞直到执行器有空闲的线程可用。