Java线程池有几种(5种常见线程池)

Java线程池有几种(5种常见线程池)-mikechen

在 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,10年+大厂架构经验,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

关注作者「mikechen」公众号,获取更多技术干货!

评论交流
    说说你的看法