3.3 5种常用的线程池
Java定义了Executor接口并在该接口中定义了execute()用于执行一个线程任务,然后通过ExecutorService实现Executor接口并执行具体的线程操作。ExecutorService接口有多个实现类可用于创建不同的线程池,如表3-2所示是5种常用的线程池。
表3-2
3.3.1 newCachedThreadPool
newCachedThreadPool用于创建一个缓存线程池。之所以叫缓存线程池,是因为它在创建新线程时如果有可重用的线程,则重用它们,否则重新创建一个新的线程并将其添加到线程池中。对于执行时间很短的任务而言,newCachedThreadPool线程池能很大程度地重用线程进而提高系统的性能。
在线程池的keepAliveTime时间超过默认的60秒后,该线程会被终止并从缓存中移除,因此在没有线程任务运行时,newCachedThreadPool将不会占用系统的线程资源。
在创建线程时需要执行申请CPU和内存、记录线程状态、控制阻塞等多项工作,复杂且耗时。因此,在有执行时间很短的大量任务需要执行的情况下,newCachedThreadPool能够很好地复用运行中的线程(任务已经完成但未关闭的线程)资源来提高系统的运行效率。具体的创建方式如下:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
3.3.2 newFixedThreadPool
newFixedThreadPool用于创建一个固定线程数量的线程池,并将线程资源存放在队列中循环使用。在newFixedThreadPool线程池中,若处于活动状态的线程数量大于等于核心线程池的数量,则新提交的任务将在阻塞队列中排队,直到有可用的线程资源,具体的创建方式如下:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
3.3.3 newScheduledThreadPool
newScheduledThreadPool创建了一个可定时调度的线程池,可设置在给定的延迟时间后执行或者定期执行某个线程任务:
ScheduledExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(3); //1:创建一个延迟3秒执行的线程 scheduledThreadPool.schedule(newRunnable(){ @Override public void run() { System.out.println("delay 3 seconds execu."); }}, 3, TimeUnit.SECONDS); //2:创建一个延迟1秒执行且每3秒执行一次的线程 scheduledThreadPool.scheduleAtFixedRate(newRunnable(){ @Override public void run() { System.out.println("delay 1 seconds, repeat execute every 3 seconds"); }},1,3, TimeUnit.SECONDS);
3.3.4 newSingleThreadExecutor
newSingleThreadExecutor线程池会保证永远有且只有一个可用的线程,在该线程停止或发生异常时,newSingleThreadExecutor线程池会启动一个新的线程来代替该线程继续执行任务:
ExecutorService singleThread = Executors.newSingleThreadExecutor();
3.3.5 newWorkStealingPool
newWorkStealingPool创建持有足够线程的线程池来达到快速运算的目的,在内部通过使用多个队列来减少各个线程调度产生的竞争。这里所说的有足够的线程指JDK根据当前线程的运行需求向操作系统申请足够的线程,以保障线程的快速执行,并很大程度地使用系统资源,提高并发计算的效率,省去用户根据CPU资源估算并行度的过程。当然,如果开发者想自己定义线程的并发数,则也可以将其作为参数传入。