• 【Java 基础篇】Executors工厂类详解


    在这里插入图片描述

    多线程编程中,线程池是一项重要的工具,它可以有效地管理和控制线程的生命周期,提高程序的性能和可维护性。Java提供了java.util.concurrent包来支持线程池的创建和管理,而Executors工厂类是其中的一部分,它提供了一些方便的方法来创建不同类型的线程池。本文将详细介绍Executors工厂类的使用方法和各种线程池的创建方式,以及一些注意事项和最佳实践。

    Executors工厂类概述

    Executors是Java中用于创建线程池的工厂类,它提供了一系列的静态工厂方法,用于创建不同类型的线程池。这些工厂方法隐藏了线程池的复杂性,使得线程池的创建变得非常简单。Executors工厂类提供的线程池有以下几种类型:

    1. newCachedThreadPool():创建一个可缓存的线程池。这个线程池的线程数量可以根据需要自动扩展,如果有可用的空闲线程,就会重用它们;如果没有可用的线程,就会创建一个新线程。适用于执行大量的短期异步任务。

    2. newFixedThreadPool(int nThreads):创建一个固定大小的线程池,其中包含指定数量的线程。线程数量是固定的,不会自动扩展。适用于执行固定数量的长期任务。

    3. newSingleThreadExecutor():创建一个单线程的线程池。这个线程池中只包含一个线程,用于串行执行任务。适用于需要按顺序执行任务的场景。

    4. newScheduledThreadPool(int corePoolSize):创建一个固定大小的线程池,用于定时执行任务。线程数量固定,不会自动扩展。适用于定时执行任务的场景。

    5. newSingleThreadScheduledExecutor():创建一个单线程的定时执行线程池。只包含一个线程,用于串行定时执行任务。

    6. newWorkStealingPool(int parallelism):创建一个工作窃取线程池,线程数量根据CPU核心数动态调整。适用于CPU密集型的任务。

    接下来,我们将详细介绍每种类型线程池的创建和使用方法。

    newCachedThreadPool()

    newCachedThreadPool()方法创建一个可缓存的线程池,这个线程池的特点是线程数量可以根据需要自动扩展,如果有可用的空闲线程,就会重用它们;如果没有可用的线程,就会创建一个新线程。这种线程池适用于执行大量的短期异步任务,例如一些需要快速响应的网络请求处理。

    创建方式

    ExecutorService executorService = Executors.newCachedThreadPool();
    
    • 1

    使用示例

    public class CachedThreadPoolExample {
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newCachedThreadPool();
    
            for (int i = 0; i < 10; i++) {
                final int taskId = i;
                executorService.submit(() -> {
                    System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
                });
            }
    
            executorService.shutdown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在上面的示例中,我们创建了一个可缓存的线程池,并提交了10个任务,线程池会根据需要自动创建新线程来执行这些任务。

    newFixedThreadPool(int nThreads)

    newFixedThreadPool(int nThreads)方法创建一个固定大小的线程池,其中包含指定数量的线程。线程数量是固定的,不会自动扩展。这种线程池适用于执行固定数量的长期任务,例如服务器中的后台处理任务。

    创建方式

    int nThreads = 5; // 指定线程数量
    ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
    
    • 1
    • 2

    使用示例

    public class FixedThreadPoolExample {
        public static void main(String[] args) {
            int nThreads = 3;
            ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
    
            for (int i = 0; i < 10; i++) {
                final int taskId = i;
                executorService.submit(() -> {
                    System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
                });
            }
    
            executorService.shutdown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在上面的示例中,我们创建了一个固定大小为3的线程池,然后提交了10个任务。线程池会按顺序执行这些任务,每次最多有3个任务同时执行。

    newSingleThreadExecutor()

    newSingleThreadExecutor()方法创建一个单线程的线程池,这个线程池中只包含一个线程,用于串行执行任务。这种线程池适用于需要按顺序执行任务的场景,例如一个任务队列中的任务需要依次执行。

    创建方式

    ExecutorService executorService = Executors.newSingleThreadExecutor();
    
    • 1

    使用示例

    public class SingleThreadExecutorExample {
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newSingleThreadExecutor();
    
            for (int i = 0; i < 10; i++) {
                final int taskId = i;
                executorService.submit(() -> {
                    System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
                });
            }
    
            executorService.shutdown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在上面的示例中,我们创建了一个单线程的线程池,并提交了10个任务。线程池会按顺序执行这些任务,保证每次只有一个任务在执行。

    newScheduledThreadPool(int corePoolSize)

    newScheduledThreadPool(int corePoolSize)方法创建一个固定大小的线程池,用于定时执行任务。线程数量是固定的,不会自动扩展。这种线程池适用于需要定时执行任务的场景,例如定时任务调度。

    创建方式

    int corePoolSize = 2; // 指定线程数量
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(corePoolSize);
    
    • 1
    • 2

    使用示例

    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    public class ScheduledThreadPoolExample {
        public static void main(String[] args) {
            int corePoolSize = 2;
            ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(corePoolSize);
    
            for (int i = 0; i < 3; i++) {
                final int taskId = i;
                scheduledExecutorService.schedule(() -> {
                    System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
                }, i + 1, TimeUnit.SECONDS);
            }
    
            scheduledExecutorService.shutdown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在上面的示例中,我们创建了一个固定大小为2的定时执行线程池,然后提交了3个定时任务,每个任务延迟执行的时间不同。

    newSingleThreadScheduledExecutor()

    newSingleThreadScheduledExecutor()方法创建一个单线程的定时执行线程池,只包含一个线程,用于串行定时执行任务。

    创建方式

    ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
    
    • 1

    使用示例

    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    public class SingleThreadScheduledExecutorExample {
        public static void main(String[] args) {
            ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
    
            for (int i = 0; i < 3; i++) {
                final int taskId = i;
                scheduledExecutorService.schedule(() -> {
                    System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
                }, i + 1, TimeUnit.SECONDS);
            }
    
            scheduledExecutorService.shutdown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在上面的示例中,我们创建了一个单线程的定时执行线程池,并提交了3个定时任务,每个任务延迟执行的时间不同。

    newWorkStealingPool(int parallelism)

    newWorkStealingPool(int parallelism)方法创建一个工作窃取线程池,线程数量根据CPU核心数动态调整。这种线程池适用于CPU密集型的任务,可以充分利用多核CPU的性能。

    创建方式

    int parallelism = Runtime.getRuntime().availableProcessors(); // 获取CPU核心数
    ExecutorService executorService = Executors.newWorkStealingPool(parallelism);
    
    • 1
    • 2

    使用示例

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    public class WorkStealingPoolExample {
        public static void main(String[] args) {
            int parallelism = Runtime.getRuntime().availableProcessors();
            ExecutorService executorService = Executors.newWorkStealingPool(parallelism);
    
            for (int i = 0; i < 10; i++) {
                final int taskId = i;
                executorService.submit(() -> {
                    System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
                });
            }
    
            executorService.shutdown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在上面的示例中,我们根据CPU核心数创建了一个工作窃取线程池,并提交了10个任务。线程池会根据CPU核心数来动态调整线程数量,以充分利用CPU的性能。

    总结

    Executors工厂类提供了多种线程池的创建方式,可以根据不同的需求选择合适的线程池类型。合理使用线程池可以提高程序的性能和可维护性,但也需要注意线程池的大小和资源管理,避免因线程过多导致的性能下降或资源耗尽问题。希望本文能够帮助读者更好地理解和使用Executors工厂类。

  • 相关阅读:
    即时通讯软件
    C语言的文件操作(炒详解)
    HTML做一个节日页面【六一儿童节】纯HTML代码
    MySQL排查篇:该如何定位并解决线上突发的Bug与疑难杂症?
    webpack 中 require.context() 的用法
    Elasticsearch:Apache spark 大数据集成
    Kafka核心原理第二弹——更新中
    安防行业S2B2C系统网站智能化大数据,S2B2C平台助力企业效率成倍提升
    Briefings in bioinformatics2022 | Knowledge-based BERT+:像计算化学家一样提取分子性质的方法
    Android学习笔记 66. Android Studio 和 Hello World
  • 原文地址:https://blog.csdn.net/qq_21484461/article/details/133101696