ExecutorService在线程池经常被使用到,下面我就来详解ExecutorService的作用与6种实现@mikechen
什么是ExecutorService
ExecutorService 是 Java 中的一个接口,属于 java.util.concurrent 包,用于管理和控制线程执行的框架。
ExecutorService 提供了一种高级的方法来管理线程池,简化了多线程编程,同时提高了资源利用率。
ExecutorService的作用
ExecutorService 接口的主要目的是为了解决直接操作线程带来的一些问题,比如手动管理线程的生命周期、创建和销毁线程的开销,以及线程间通信等问题。
它在多线程环境中有许多重要作用:
- 线程池管理:
ExecutorService
封装了线程池的概念,它通过管理一组预创建的线程,可以有效地重用线程,从而降低了线程创建和销毁的开销。 - 任务调度:
ExecutorService
允许你提交任务,然后自动调度线程来执行这些任务,你不必手动创建和启动线程,从而减少了因线程管理而引入的错误。 - 异步执行: 提交任务给
ExecutorService
后,它会异步地执行任务,使得你的程序可以继续执行其他操作,而不需要等待任务完成。 - 异常处理:
ExecutorService
可以捕获和处理任务执行过程中可能抛出的异常,从而更好地控制和处理错误情况。
ExecutorService的实现
1.ThreadPoolExecutor
ThreadPoolExecutor
是一个灵活的线程池实现,允许你自定义线程池的各种参数。
如下所示:
ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, // corePoolSize 5, // maximumPoolSize 60, TimeUnit.SECONDS, // keepAliveTime new LinkedBlockingQueue<Runnable>() // workQueue ); executor.submit(() -> System.out.println("Task executed.")); executor.shutdown();
上就自定义了:核心线程数、最大线程数、线程空闲时间等。
2.ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor 是支持计划执行任务的线程池,可以延迟任务执行或者周期性地执行任务。
如下所示:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); executor.schedule(() -> System.out.println("Scheduled task"), 5, TimeUnit.SECONDS); executor.scheduleAtFixedRate(() -> System.out.println("Recurring task"), 0, 2, TimeUnit.SECONDS);
它允许你安排任务在未来的某个时间点执行,或者以固定时间间隔重复执行。
3.FixedThreadPool
FixedThreadPool 是一个具有固定大小的线程池,适用于需要限制并发线程数的情况。
如下所示:
ExecutorService executor = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int taskNumber = i; executor.submit(() -> System.out.println("Task " + taskNumber + " executed.")); } executor.shutdown();
上面创建了一个具有固定线程数的线程池,一旦线程被创建,它们会一直存在,直到线程池被关闭。
4.CachedThreadPool
Executors.newCachedThreadPool()
方法返回一个根据需求自动调整大小的线程池。
如下所示:
ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int taskNumber = i; executor.submit(() -> System.out.println("Task " + taskNumber + " executed.")); } executor.shutdown();
线程池会根据任务的数量自动创建新线程,当线程空闲一段时间后,它们会被回收。
5.SingleThreadExecutor
Executors.newSingleThreadExecutor()
方法返回一个只有一个线程的线程池,用于顺序执行任务。
如下所示:
ExecutorService executor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++) { final int taskNumber = i; executor.submit(() -> System.out.println("Task " + taskNumber + " executed.")); } executor.shutdown();
适用于需要确保任务按顺序执行的场景。
6.WorkStealingPool
Executors.newWorkStealingPool()
方法返回一个基于工作窃取算法的线程池。
如下所示:
ExecutorService executor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++) { final int taskNumber = i; executor.submit(() -> System.out.println("Task " + taskNumber + " executed.")); } executor.shutdown();
WorkStealingPool 是基于工作窃取算法的线程池,不同线程维护自己的任务队列,可以从其他线程的队列中窃取任务来执行。
陈睿mikechen
十余年BAT架构经验,资深技术专家,就职于阿里、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》