likes
comments
collection
share

多线程-线程池

作者站长头像
站长
· 阅读数 13

如何使用线程池?

如何创建线程池?两种方法: 1、基于工厂线程池类 2、基于自定义线程池类

线程池工厂类

线程池是一种用于管理和复用线程的机制,可以有效地处理多线程任务。以下是一个简单的Java线程池示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池,其中包含5个线程
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        // 创建10个任务并提交给线程池
        for (int i = 0; i < 10; i++) {
            Runnable task = new Task(i);
            executorService.execute(task);
        }

        // 关闭线程池
        executorService.shutdown();
    }

    static class Task implements Runnable {
        private int taskId;

        public Task(int taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            System.out.println("任务 " + taskId + " 正在执行");
            // 模拟任务执行时间
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务 " + taskId + " 执行完毕");
        }
    }
}

这个示例创建了一个固定大小为5的线程池,然后提交了10个任务给线程池。线程池会自动分配这些任务给可用的线程,并在任务执行完毕后继续使用这些线程。最后,线程池被关闭以释放资源。

您可以根据自己的需求调整线程池的大小和任务内容。


这个是简单的使用,即参数都帮你配置好了。

本质是基于这个工厂类Executors,来创建线程池。基于工厂类创建的线程池,都是固定功能线程池。比如,缓存线程池,固定线程池,调度线程池,单个线程线程池。这些线程池都是包含固定功能,如果你确实需要对应功能的线程池,就使用那个。

自定义参数线程池使用哪个?ThreadPoolExecutor

要创建一个自定义参数的线程池,您可以使用ThreadPoolExecutor类,这允许您更灵活地配置线程池的参数。以下是一个示例代码,演示如何创建自定义参数的线程池:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CustomThreadPoolDemo {
    public static void main(String[] args) {
        // 定义线程池的参数
        int corePoolSize = 3; // 核心线程数
        int maxPoolSize = 5;  // 最大线程数
        long keepAliveTime = 10; // 非核心线程的闲置超时时间(秒)
        int queueCapacity = 10;  // 任务队列容量

        // 创建自定义参数的线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            corePoolSize,
            maxPoolSize,
            keepAliveTime,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(queueCapacity)
        );

        // 提交任务给线程池
        for (int i = 0; i < 10; i++) {
            Runnable task = new Task(i);
            executor.execute(task);
        }

        // 关闭线程池
        executor.shutdown();
    }

    static class Task implements Runnable {
        private int taskId;

        public Task(int taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            System.out.println("任务 " + taskId + " 正在执行");
            // 模拟任务执行时间
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务 " + taskId + " 执行完毕");
        }
    }
}

在上面的示例中,我们使用ThreadPoolExecutor类来创建线程池,可以自定义核心线程数、最大线程数、闲置线程的超时时间以及任务队列的容量。这允许您根据自己的需求灵活配置线程池的参数。当然,您可以根据实际情况进行进一步的调整。

ThreadPoolExecutor和Executors区别?

ThreadPoolExecutorExecutors都与线程池相关,但它们在功能和用法上有一些重要的区别。

  1. 灵活性

    • ThreadPoolExecutor:它是java.util.concurrent.ThreadPoolExecutor类的实现,允许您完全自定义线程池的各个参数,包括核心线程数、最大线程数、闲置线程的存活时间、任务队列类型和容量等。这使您能够精确地控制线程池的行为,以满足特定的需求。

    • ExecutorsExecutors是一个工厂类,提供了一些预定义的线程池创建方法,如newFixedThreadPoolnewCachedThreadPool等。这些方法返回的线程池具有固定的配置参数,例如,newFixedThreadPool返回一个固定大小的线程池,newCachedThreadPool返回一个根据需要自动调整大小的线程池。虽然这些方法非常方便,但它们的配置参数是固定的,不太适合复杂或特定的线程池需求。

  2. 配置参数

    • ThreadPoolExecutor:您可以精确地指定线程池的各个参数,以满足您的需求。这包括核心线程数、最大线程数、线程的闲置时间、任务队列类型和容量等。这种方式更适用于需要定制化的线程池。

    • ExecutorsExecutors提供的线程池创建方法通常有一组固定的参数配置,无法对这些参数进行详细的自定义。这适合于一些常见的用例,但不太适用于特殊要求。

  3. 适用性

    • ThreadPoolExecutor:适用于需要高度定制化线程池的情况,例如,需要特定线程数、队列类型、拒绝策略等的应用。

    • Executors:适用于简单的线程池需求,可以通过几个预定义的工厂方法快速创建线程池,但不支持深度定制。

综上所述,如果您需要更多的线程池配置自由度和精确控制,应该使用ThreadPoolExecutor。而如果您只需要一些常见用例的线程池,可以使用Executors提供的快捷方式。根据您的具体需求选择适合的工具。

Executors的底层实现是不是都是ThreadPoolExecutor?

是的,Executors 类的底层实现通常会使用 ThreadPoolExecutor 来创建不同类型的线程池。ThreadPoolExecutor 是 Java 中用于实现线程池的核心类,Executors 类中的工厂方法会使用 ThreadPoolExecutor 来创建不同配置的线程池实例。

例如,Executors.newFixedThreadPool(int nThreads) 方法会创建一个固定大小的线程池,它的底层实现就是使用 ThreadPoolExecutor 来创建的,只不过参数都已经预先设置好,用户不需要手动配置。

虽然 Executors 提供了一些方便的工厂方法来创建线程池,但请注意,这些方法通常使用一组默认的参数配置,可能不适合所有情况。如果需要更精细的控制和自定义线程池的参数,建议直接使用 ThreadPoolExecutor 类来创建线程池。这样您可以根据实际需求进行配置,以满足特定的线程池需求。

总结

1、一般情况下,都是使用自定义线程池。为什么?因为要配置线程数量参数,还要配置为有界阻塞队列ArrayBlockingQueue(默认是无界阻塞队列LinkedBlockingQueue),还有拒绝策略。

2、除非确实需要使用固定功能的线程池类,才会使用基于工厂类创建固定功能的线程池类。


工厂类创建的固定功能线程池类,底层其实也是基于自定义线程池类ThreadPoolExecutor。只不过,一个是帮你把参数配置好了,你直接用。一个是你自己配置。工作使用线程池的时候,一般都是需要自己配置,所以一般都使用ThreadPoolExecutor。