在 Java 中有几种类型的线程池可以用于处理多线程任务,以下是常见的5种Java线程池@mikechen
FixedThreadPool(固定线程池)
固定线程池会创建一个固定数量的线程,并在池中保持这些线程的数量不变。
如下所示:
// 创建一个固定线程数量为 3 的线程池 ExecutorService executor = Executors.newFixedThreadPool(3); // 提交任务 for (int i = 0; i < 10; i++) { final int taskId = i; executor.execute(() -> { System.out.println("Task " + taskId + " is being executed by thread " + Thread.currentThread().getName()); }); } // 关闭线程池 executor.shutdown();
适用场景:
- 当有固定数量的并发任务需要处理时。
- 希望限制线程数量,防止过多线程导致资源耗尽。
注意事项:
- 由于线程数量是固定的,如果同时有大量任务提交,可能会导致工作队列积压,因此需要根据实际情况来选择线程池的大小。
- 当任务量较小时,固定线程池可能会浪费一些线程资源,如果在任务量不确定的情况下,可以考虑使用缓存线程池。
CachedThreadPool(缓存线程池)
缓存线程池会根据需要动态地创建线程,并在一段时间内重用空闲线程,通常是60秒。
如下所示:
ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int taskId = i; executor.execute(() -> { System.out.println("Task " + taskId + " is being executed by thread " + Thread.currentThread().getName()); }); } executor.shutdown();
适用场景:
缓存线程池适用于短期任务数量不确定的场景,特别是在处理大量的短期任务时,它可以根据任务的数量动态地分配和回收线程,以提供最佳的并发性能。
注意事项:
- 虽然缓存线程池在短期任务处理上非常高效,但在处理长期任务时,可能会导致过多的线程占用系统资源。
- 当不再需要线程池时,务必调用
shutdown()
方法来释放线程资源,避免资源泄漏。
SingleThreadExecutor(单线程池)
单线程池只有一个工作线程,用于按照顺序执行提交的任务,所有任务按照它们的提交顺序在同一个线程中执行。
如下所示 :
ExecutorService executor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int taskId = i; executor.execute(() -> { System.out.println("Task " + taskId + " is being executed by thread " + Thread.currentThread().getName()); }); } executor.shutdown();
适用场景:
- 单线程池适用于需要按顺序执行任务的场景,例如需要保证任务的顺序执行,避免并发带来的问题。
- 也适用于需要在单个线程中执行任务,以避免并发的复杂性。
注意事项:
- 单线程池适用于保证任务顺序执行的场景,但不适合需要高并发处理的情况。
- 虽然只有一个线程在执行任务,但如果有异常抛出,线程池会创建一个新线程来继续执行后续任务。
ScheduledThreadPool(调度线程池)
调度线程池(ScheduledThreadPool)是 Java 中一种特殊的线程池类型,用于执行定时任务或周期性任务。
如下所示:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); Runnable task = () -> { System.out.println("Scheduled task executed at " + System.currentTimeMillis()); }; // 延迟2秒执行任务 executor.schedule(task, 2, TimeUnit.SECONDS); // 延迟1秒后每3秒执行一次 executor.scheduleAtFixedRate(task, 1, 3, TimeUnit.SECONDS); // 关闭线程池 executor.shutdown();
适用场景:
调度线程池适用于需要按计划执行任务的场景,例如:定时生成报表、定时数据清理、周期性检查等。
注意事项:
- 调度线程池适用于需要按计划执行任务的场景,但需要考虑任务执行时间和调度间隔,避免任务堆积或执行过长导致的问题。
- 当不再需要线程池时,务必调用
shutdown()
方法来释放线程资源,避免资源泄漏。
WorkStealingPool(工作窃取线程池)
工作窃取线程池是 Java 7 引入的一种线程池,它基于 “工作窃取” 的概念。
每个线程维护自己的任务队列,当一个线程的任务队列为空时,它可以从其他线程的任务队列中窃取任务来执行。
如下所示:
ForkJoinPool executor = new ForkJoinPool(); int[] array = new int[1000000]; RecursiveTask<Integer> task = new CustomTask(array, 0, array.length); executor.invoke(task); executor.shutdown();
这种线程池适用于一些需要大量计算的并行任务。
以上就是5种Java线程池的用法和适用场景,你可以选择适合你应用程序的线程池类型,以优化并发处理和资源利用。
mikechen
mikechen睿哥,10年+大厂架构经验,资深技术专家,就职于阿里、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》