ToB企服应用市场:ToB评测及商务社交产业平台

标题: Java Executors类的9种创建线程池的方法及应用场景分析 [打印本页]

作者: 前进之路    时间: 2024-7-9 15:17
标题: Java Executors类的9种创建线程池的方法及应用场景分析
在Java中,Executors 类提供了多种静态工厂方法来创建不同类型的线程池。在学习线程池的过程中,一定避不开Executors类,掌握这个类的使用、原理、使用场景,对于实际项目开发时,运用自如,以下是一些常用的方法,V哥来一一细说:
这些方法提供了灵活的方式来创建和管理线程池,以满足不同的并发需求,下面 V 哥来一一介绍一下9个方法的实现以及使用场景。
1. newCachedThreadPool()

newCachedThreadPool 方法是 Java java.util.concurrent 包中的 Executors 类的一个静态工厂方法。这个方法用于创建一个可缓存的线程池,它能够根据需要创建新线程,并且当线程空闲超过一定时间后,线程会被终止并从线程池中移除。
下面是 newCachedThreadPool 方法的大致实现原理和源代码分析:
实现原理
源代码分析
在 Java 的 java.util.concurrent 包中,Executors 类并没有直接提供 newCachedThreadPool 的实现,而是通过调用 ThreadPoolExecutor 类的构造函数来实现的。以下是 ThreadPoolExecutor 构造函数的调用示例:
  1. public static ExecutorService newCachedThreadPool() {
  2.     return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
  3.                                    60L, TimeUnit.SECONDS,
  4.                                    new SynchronousQueue<Runnable>());
  5. }
复制代码
参数解释:
实现过程
这种操持使得 newCachedThreadPool 非常得当处置惩罚大量短生命周期的任务,因为它可以动态地调解线程数量以适应任务负载的变化。然而,由于它可以创建无限多的线程,如果没有适当的任务队列来控制任务的数量,可能会导致资源耗尽。因此,在使用 newCachedThreadPool 时,需要谨慎考虑任务的特性和体系的资源限制。
使用场景:
实用于执行大量短期异步任务,尤其是任务执行时间不确定的情况。比方,Web服务器处置惩罚大量并发请求,大概异步日记记录。
2. newFixedThreadPool(int nThreads)

newFixedThreadPool(int nThreads) 是 Java 中 java.util.concurrent 包的 Executors 类的一个静态工厂方法。这个方法用于创建一个固定大小的线程池,它能够确保线程池中始终有固定数量的线程在工作。
以下是 newFixedThreadPool 方法的实现原理、源代码分析以及实现过程:
实现原理
源代码分析
newFixedThreadPool 方法是通过调用 ThreadPoolExecutor 类的构造函数来实现的。以下是 ThreadPoolExecutor 构造函数的调用示例:
  1. public static ExecutorService newFixedThreadPool(int nThreads) {
  2.     return new ThreadPoolExecutor(
  3.         nThreads, // 核心线程数
  4.         nThreads, // 最大线程数
  5.         0L,      // 线程空闲时间,这里设置为0,表示线程不会空闲
  6.         TimeUnit.MILLISECONDS,
  7.         new LinkedBlockingQueue<Runnable>() // 使用阻塞队列来存储任务
  8.     );
  9. }
复制代码
参数解释:
实现过程
这种操持使得 newFixedThreadPool 非常得当处置惩罚大量且连续的任务,因为它可以保证任务以固定的线程数量并行执行,同时避免了线程数量的无限制增长。然而,由于线程池的大小是固定的,如果任务提交的速率超过了线程池的处置惩罚能力,可能会导致任务在队列中等待较长时间。因此,在使用 newFixedThreadPool 时,需要根据任务的特性和预期的负载来合理设置 nThreads 的值。
使用场景:
实用于执行大量长期运行的任务,其中线程数量需要固定。比方,同时运行多个数据加载或数据处置惩罚任务,且希望限制并发数以避免资源过载。
3. newSingleThreadExecutor()

newSingleThreadExecutor 是 Java 中 java.util.concurrent 包的 Executors 类的一个静态工厂方法,用于创建一个单线程的执行器。这个执行器确保所有任务都按照任务提交的顺序,在一个线程中顺序执行。
以下是 newSingleThreadExecutor 方法的实现原理、源代码分析以及实现过程:
实现原理
源代码分析
newSingleThreadExecutor 方法同样是通过调用 ThreadPoolExecutor 类的构造函数来实现的。以下是 ThreadPoolExecutor 构造函数的调用示例:
  1. public static ExecutorService newSingleThreadExecutor() {
  2.     return new ThreadPoolExecutor(
  3.         1, // 核心线程数
  4.         1, // 最大线程数
  5.         0L, TimeUnit.MILLISECONDS, // 线程空闲时间,这里设置为0,表示线程不会空闲
  6.         new LinkedBlockingQueue<Runnable>() // 使用阻塞队列来存储任务
  7.     );
  8. }
复制代码
参数解释:
实现过程
这种操持使得 newSingleThreadExecutor 非常得当处置惩罚需要保证任务顺序的场景,比方,当任务之间有依赖关系大概需要按照特定顺序执行时。同时,由于只有一个线程,这也避免了多线程环境下的并发问题。然而,由于只有一个线程执行任务,这也限制了并行处置惩罚的能力,如果任务执行时间较长,可能会导致后续任务等待较长时间。因此,在使用 newSingleThreadExecutor 时,需要根据任务的特性和对顺序的要求来决定是否实用。
使用场景:
实用于需要保证任务顺序执行的场景,比方,顺序处置惩罚队列中的消息或事件。也实用于需要单个后台线程连续处置惩罚周期性任务的情况。
4. newScheduledThreadPool(int corePoolSize)

newScheduledThreadPool 是 Java 中 java.util.concurrent 包的 Executors 类的一个静态工厂方法,用于创建一个固定大小的线程池,这个线程池支持定时以及周期性的任务执行。
以下是 newScheduledThreadPool 方法的实现原理、源代码分析以及实现过程:
实现原理
源代码分析
newScheduledThreadPool 方法是通过调用 ScheduledThreadPoolExecutor 类的构造函数来实现的。以下是 ScheduledThreadPoolExecutor 构造函数的调用示例:
  1. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
  2.     return new ScheduledThreadPoolExecutor(corePoolSize);
  3. }
复制代码
这里的 ScheduledThreadPoolExecutor 是 ThreadPoolExecutor 的一个子类,专门为执行定时任务操持。ScheduledThreadPoolExecutor 构造函数的参数 corePoolSize 界说了线程池中核心线程的数量。
ScheduledThreadPoolExecutor 内部使用了一个 DelayedWorkQueue 作为任务队列,这个队列能够按照任务的预定执行时间对任务进行排序。
实现过程
特点
使用 newScheduledThreadPool 创建的线程池非常得当需要执行定时任务的场景,比方,定期执行的后台任务、定时检查等。然而,由于它是基于固定大小的线程池,以是在高负载情况下,任务可能会排队等待执行,这需要在操持时考虑适当的 corePoolSize 以满足性能要求。
使用场景:
实用于需要定期执行任务或在未来某个时间点执行任务的场景。比方,定时备份数据、定时发送提醒等。
5. newWorkStealingPool(int parallelism)

newWorkStealingPool 是 Java 8 中新增的 java.util.concurrent 包的 Executors 类的一个静态工厂方法。这个方法用于创建一个工作窃取(Work-Stealing)线程池,它能够提高并行任务的执行效率,特殊是在多处置惩罚器体系上。
实现原理
源代码分析
newWorkStealingPool 方法是通过调用 ForkJoinPool 类的静态工厂方法 commonPoolFor 来实现的。以下是 ForkJoinPool 构造函数的调用示例:
  1. public static ExecutorService newWorkStealingPool(int parallelism) {
  2.     return new ForkJoinPool(
  3.         parallelism,
  4.         ForkJoinPool.defaultForkJoinWorkerThreadFactory,
  5.         null, // 没有未处理的异常处理器
  6.         false // 不是一个异步任务
  7.     );
  8. }
复制代码
参数解释:
ForkJoinPool 内部使用了 ForkJoinWorkerThread 来执行任务,并且每个线程都有一个 ForkJoinQueue 来存储任务。
实现过程
特点
使用 newWorkStealingPool 创建的线程池非常得当于需要高并发和高吞吐量的场景,尤其是在多处置惩罚器体系上。然而,由于工作窃取机制,它可能不实用于任务执行时间非常短大概任务数量非常少的场景,因为窃取任务本身可能会引入额外的开销。
使用场景:
实用于工作量不均匀或可分解为多个小任务的并行计算任务。比方,图像处置惩罚、数据分析等,可以在多核处置惩罚器上有效利用所有核心。
6. newSingleThreadScheduledExecutor()

newSingleThreadScheduledExecutor 是 Java 中 java.util.concurrent 包的 Executors 类的一个静态工厂方法。这个方法用于创建一个单线程的调度执行器,它可以安排命令在给定的耽误后运行,大概定期地执行。
以下是 newSingleThreadScheduledExecutor 方法的实现原理、源代码分析以及实现过程:
实现原理
源代码分析
newSingleThreadScheduledExecutor 方法是通过调用 ScheduledThreadPoolExecutor 类的构造函数来实现的。以下是 ScheduledThreadPoolExecutor 构造函数的调用示例:
  1. public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
  2.     return new ScheduledThreadPoolExecutor(1);
  3. }
复制代码
这里,ScheduledThreadPoolExecutor 是 ExecutorService 的一个实现,专门为执行定时任务操持。构造函数只有一个参数,即核心线程数,这里设置为1,表示这是一个单线程的执行器。
ScheduledThreadPoolExecutor 内部使用了一个 DelayedWorkQueue 作为任务队列,这个队列能够按照任务的预定执行时间对任务进行排序。
实现过程
特点
使用 newSingleThreadScheduledExecutor 创建的执行器可以提供强盛的定时任务功能,同时保持任务执行的顺序性。然而,由于只有一个线程执行任务,这也限制了并行处置惩罚的能力,如果任务执行时间较长,可能会导致后续任务等待较长时间。因此,在使用 newSingleThreadScheduledExecutor 时,需要根据任务的特性和对顺序的要求来决定是否实用。
使用场景:
实用于需要单个后台线程按操持执行任务的场景。比方,定时检查体系状态、定时执行维护任务等。
7. privilegedThreadFactory()

privilegedThreadFactory 是 Java 中 java.util.concurrent 包的 Executors 类的一个静态工厂方法,用于创建一个线程工厂,该工厂能够产生具有特权访问的线程。这意味着这些线程可以加载体系属性和库,并且可以访问文件体系。
以下是 privilegedThreadFactory 方法的实现原理、源代码分析以及实现过程:
实现原理
源代码分析
在 Java 的标准库中,privilegedThreadFactory 方法的实现细节并未公开,因为它是一个私有方法。然而,我们可以分析其大致工作原理。privilegedThreadFactory 方法的调用示比方下:
  1. public static ThreadFactory privilegedThreadFactory() {
  2.     return new PrivilegedThreadFactory();
  3. }
复制代码
这里,PrivilegedThreadFactory 是 Executors 类的一个私有静态内部类,它实现了 ThreadFactory 接口。ThreadFactory 接口界说了一个 newThread(Runnable r) 方法,用于创建新的线程。
实现过程
示例代码
虽然我们不能查看 privilegedThreadFactory 的具体实现,但是我们可以提供一个示例实现,以展示如何创建具有特权访问的线程:
  1. public class PrivilegedThreadFactory implements ThreadFactory {
  2.     @Override
  3.     public Thread newThread(Runnable r) {
  4.         return AccessController.doPrivileged(new PrivilegedAction<>() {
  5.             @Override
  6.             public Thread run() {
  7.                 return new Thread(r);
  8.             }
  9.         });
  10.     }
  11. }
复制代码
在这个示例中,PrivilegedAction 是一个实现了 PrivilegedAction 接口的匿名类,其 run 方法创建了一个新的线程。AccessController.doPrivileged 方法用于执行一个特权操作,这里是为了确保线程创建过程中具有必要的权限。
特点
使用 privilegedThreadFactory 可以确保线程在执行任务时具有适当的安全权限,从而避免安全非常。然而,需要注意的是,过度使用特权访问可能会带来安全风险,因此在操持应用程序时应谨慎使用。
使用场景:
实用于需要线程具有更高权限来访问体系资源的场景。比方,需要访问体系属性或执行文件I/O操作的应用程序。
8. defaultThreadFactory()

defaultThreadFactory 是 Java 中 java.util.concurrent 包的 Executors 类的一个静态工厂方法,用于创建一个默认的线程工厂。这个线程工厂生成的线程没有特殊的权限,它们是普通的线程,具有标准的访问权限。
以下是 defaultThreadFactory 方法的实现原理、源代码分析以及实现过程:
实现原理
源代码分析
Java 的 defaultThreadFactory 方法的具体实现细节并未完全公开,因为它是 Executors 类的一个私有静态方法。但是,我们可以根据 Java 的 ThreadFactory 接口和一些公开的源代码片段来分析其大致实现。
以下是 defaultThreadFactory 方法的调用示例:
  1. public static ThreadFactory defaultThreadFactory() {
  2.     return new DefaultThreadFactory();
  3. }
复制代码
这里,DefaultThreadFactory 是 Executors 类的一个私有静态内部类,它实现了 ThreadFactory 接口。ThreadFactory 接口界说了一个 newThread(Runnable r) 方法,用于创建新的线程。
实现过程
示例代码
虽然我们不能查看 defaultThreadFactory 的具体实现,但是我们可以提供一个示例实现,以展示如何创建具有默认属性的线程:
  1. public class DefaultThreadFactory implements ThreadFactory {
  2.     private static final AtomicInteger poolNumber = new AtomicInteger(1);
  3.     private final ThreadGroup group;
  4.     private final AtomicInteger threadNumber = new AtomicInteger(1);
  5.     private final String namePrefix;
  6.     DefaultThreadFactory() {
  7.         SecurityManager s = System.getSecurityManager();
  8.         group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
  9.         namePrefix = "pool-" +
  10.                      poolNumber.getAndIncrement() +
  11.                      "-thread-";
  12.     }
  13.     public Thread newThread(Runnable r) {
  14.         Thread t = new Thread(group, r,
  15.                               namePrefix + threadNumber.getAndIncrement(),
  16.                               0);
  17.         if (t.isDaemon())
  18.             t.setDaemon(false);
  19.         if (t.getPriority() != Thread.NORM_PRIORITY)
  20.             t.setPriority(Thread.NORM_PRIORITY);
  21.         return t;
  22.     }
  23. }
复制代码
在这个示例中,DefaultThreadFactory 使用 AtomicInteger 来确保线程池和线程编号的唯一性。创建的线程名称具有前缀 "pool-x-thread-y",其中 x 和 y 是自增的数字。线程不是守护线程,且优先级设置为 Thread.NORM_PRIORITY。
特点
使用 defaultThreadFactory 可以确保线程在执行任务时具有标准的安全和执行属性,得当大多数常规用途。然而,如果应用程序需要特殊的线程属性,如守护线程或不同的优先级,可能需要自界说线程工厂。
使用场景:
实用于大多数标准应用程序,需要创建具有默认属性的线程。这是大多数 ExecutorService 实现的默认选择。
9. unconfigurableExecutorService(ExecutorService executor)

unconfigurableExecutorService 是 Java 中 java.util.concurrent 包的 Executors 类的一个静态工厂方法。这个方法用于创建一个不可配置的 ExecutorService 包装器,这意味着一旦包装后的 ExecutorService 被创建,就不能更改其配置,比如不能修改其线程池大小或任务队列等。
以下是 unconfigurableExecutorService 方法的实现原理、源代码分析以及实现过程:
实现原理
源代码分析
unconfigurableExecutorService 方法的具体实现细节并未完全公开,因为它是 Executors 类的一个私有静态方法。但是,我们可以根据 Java 的 ExecutorService 接口和代理机制来分析其大致实现。
以下是 unconfigurableExecutorService 方法的调用示例:
  1. public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
  2.     return new FinalizableDelegatedExecutorService(executor);
  3. }
复制代码
这里,FinalizableDelegatedExecutorService 是 Executors 类的一个私有静态内部类,它实现了 ExecutorService 接口,并代理了对另一个 ExecutorService 的调用。
实现过程
示例代码
下面V哥来模拟一个示例实现,以展示如何创建一个不可配置的 ExecutorService 代理:
  1. public class UnconfigurableExecutorService implements ExecutorService {
  2.     private final ExecutorService executor;
  3.     public UnconfigurableExecutorService(ExecutorService executor) {
  4.         this.executor = executor;
  5.     }
  6.     @Override
  7.     public void shutdown() {
  8.         throw new UnsupportedOperationException("Shutdown not allowed");
  9.     }
  10.     @Override
  11.     public List<Runnable> shutdownNow() {
  12.         throw new UnsupportedOperationException("Shutdown not allowed");
  13.     }
  14.     @Override
  15.     public boolean isShutdown() {
  16.         return executor.isShutdown();
  17.     }
  18.     @Override
  19.     public boolean isTerminated() {
  20.         return executor.isTerminated();
  21.     }
  22.     @Override
  23.     public void execute(Runnable command) {
  24.         executor.execute(command);
  25.     }
  26.     // 其他 ExecutorService 方法的实现,遵循相同的模式
  27. }
复制代码
在这个示例中,UnconfigurableExecutorService 拦截了 shutdown 和 shutdownNow 方法,并抛出了非常。其他方法则直接转发到原始的 ExecutorService。
特点
使用 unconfigurableExecutorService 可以为现有的 ExecutorService 提供一个安全层,确保它们的状态不会被意外地更改。这对于在多线程环境中共享 ExecutorService 时特殊有用。
使用场景:
实用于需要确保线程池配置在创建后不被更改的场景。比方,当多个组件共享同一个线程池时,可以防止一个组件意外修改配置。
末了

以上是V哥在授课过程中整理的关于Executors 9种创建线程池的方法及原理分析,分享给各人,希望对正在学习 Java 的你有所帮助,每天分享技术干货,欢迎关注威哥爱编程,你的鼓励是V哥技术创作路上的助推器,不喜勿喷,感谢。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4