JAVA多线程之ThreadPoolExecutor创建线程池

本文详细介绍了Java中线程池的两种创建方式(ThreadPoolExecutor和Executors),重点讲解了ThreadPoolExecutor的构造参数及其含义,并展示了如何自定义拒绝策略。作者通过实例演示了如何使用ThreadPoolExecutor创建线程池并执行任务。
摘要由CSDN通过智能技术生成

📢博客主页:折戏花

📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

📢本文由折戏花编写,首发于CSDN🙉

本文主要简单介绍一下线程池的创建使用

一、线程池创建方式

线程池的创建⽅法可分为 2 类:

一种通过 ThreadPoolExecutor 创建的线程池;

一种通过 Executors 创建的线程池。

线程池的创建⽅式总共有 7 种(其中 6 种是通过 Executors 创建的, 1 种是通过ThreadPoolExecutor 创建的):

1、Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待;

2、Executors.newCachedThreadPool:创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数不够,则新建线程;

3、Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执⾏顺序;

4、Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池;

5、Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执⾏延迟任务的线程池;

6、Executors.newWorkStealingPool:创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK1.8 新增】。

7、ThreadPoolExecutor:最原始的创建线程池的⽅式。也是本文主要介绍的线程池创建方式

二、ThreadPoolExecutor介绍

阿里巴巴的《Java开发手册》已经像我们说明了线程池创建方式的选择:
线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

说明:Executors 返回的线程池对象的弊端如下:
FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
CachedThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

通过看源码我们可以知道ThreadPoolExecutor继承自AbstractExecutorService,而AbstractExecutorService实现了ExecutorService接口
在这里插入图片描述
通过ThreadPoolExecutor的构造函数我们可以看到ThreadPoolExecutor包含了7个核心参数,我们介绍下这些参数的含义
参数含义:
1、corePoolSize:核心线程池的大小,即线程池中始终存活的线程数
2、maximumPoolSize:最大线程池的大小,即最大线程数,线程池中允许的最大线程数,当线程池的任务队列满了之后可以创建的最大线程数
3、keepAliveTime:最大线程数可以存活的时间,当线程中没有任务执行时,最大线程就会销毁一部分,最终保持核心线程数量的线程
4、unit:keepAliveTime的时间单位,有以下7种

TimeUnit.DAYS:天
TimeUnit.HOURS:小时
TimeUnit.MINUTES:分
TimeUnit.SECONDS:秒
TimeUnit.MILLISECONDS:毫秒
TimeUnit.MICROSECONDS:微妙
TimeUnit.NANOSECONDS:纳秒

5、workQueue:用来暂时保存等待执行的任务的工作队列,是一个阻塞队列,均为线程安全,它包含以下 7 种类型:较常用的是 LinkedBlockingQueue 和 Synchronous,线程池的排队策略与 BlockingQueue 有关,有以下7种队列

ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。与SynchronousQueue类似,还含有非阻塞方法。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

6、threadFactory:线程工厂提供线程的创建方式,默认使用Executors.defaultThreadFactory()
7、handler:当线程池所处理的任务数超过其承载容量或关闭后继续有任务提交时,所调用的拒绝策略,提供了4种拒绝策略,默认策略为 AbortPolicy

AbortPolicy:拒绝并抛出异常。
CallerRunsPolicy:使用当前调用的线程来执行此任务。
DiscardOldestPolicy:抛弃队列头部(最旧)的一个任务,并执行当前任务。
DiscardPolicy:忽略并抛弃当前任务。

三、ThreadPoolExecutor创建线程池

import java.util.concurrent.*;

public class ThreadPoolExecutorExample {
    public static void main(String[] args) {
        // 创建一个线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                5, // 最大线程数
                1, // 线程空闲时间
                TimeUnit.SECONDS, // 时间单位
                new ArrayBlockingQueue<>(5), // 任务队列
                new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
        );

        // 提交任务给线程池
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.execute(() -> {
                System.out.println("Task " + taskId + " is running.");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskId + " is completed.");
            });
        }

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

执行结果
在这里插入图片描述
从结果中我们可以看到队列大小小于线程任务时,我们的线程池则会创建线程数刚好为maximumPoolSize的值

四、自定义拒绝策略

除了上述的4种拒绝策略,我们还可以通过实现RejectedExecutionHandler 接口来自定义拒绝策略


public class CustomRejectionPolicy implements RejectedExecutionHandler {
 
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        //这是自定义策略
    }
 }
 public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("当前任务被执行线程:" + Thread.currentThread().getName());
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1,
                1,
                100,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1),
                new CustomRejectionPolicy());
        // 添加并执行任务
        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);
        // 关闭线程池
        executor.shutdown();
    }

执行结果
在这里插入图片描述

  • 38
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 好的,以下是用 JavaThreadPoolExecutor 创建线程池的示例代码: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; public class ThreadPoolExample { public static void main(String[] args) { int corePoolSize = 2; int maximumPoolSize = 4; long keepAliveTime = 10; ExecutorService executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, java.util.concurrent.TimeUnit.SECONDS, new java.util.concurrent.LinkedBlockingQueue<Runnable>() ); // 提交任务 for (int i = 0; i < 10; i++) { executor.execute(new Task(i)); } // 关闭线程池 executor.shutdown(); } static class Task implements Runnable { private int id; public Task(int id) { this.id = id; } public void run() { System.out.println("Task " + id + " is running."); } } } ``` 在这个例子中,我们使用 ThreadPoolExecutor 创建了一个线程池。它的参数包括: - corePoolSize:线程池中核心线程的数量; - maximumPoolSize:线程池中最大线程数; - keepAliveTime:线程池中非核心线程的超时时间; - TimeUnit:超时时间的单位; - BlockingQueue:用于缓存等待执行的任务的队列。 我们还定义了一个 Task 类来模拟需要执行的任务。在主函数中,我们提交了 10 个任务给线程池,并在任务执行结束后关闭了线程池。 ### 回答2: 使用java中的ThreadPoolExecutor类可以很方便地创建线程池。首先,我们需要导入java.util.concurrent包,在代码中创建ThreadPoolExecutor对象。 ThreadPoolExecutor类的构造函数有多个参数,其中最重要的是corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue和threadFactory。corePoolSize指定了线程池中保留的线程数,maximumPoolSize指定了线程池中允许的最大线程数。keepAliveTime和unit用于指定超过corePoolSize数量的空闲线程在被终止之前等待新任务的最长时间。workQueue用于存储等待执行的任务。threadFactory用于创建新线程。 下面是一个简单的示例代码: ``` import java.util.concurrent.*; public class ThreadPoolExample { public static void main(String[] args) { int corePoolSize = 5; int maximumPoolSize = 10; long keepAliveTime = 1; TimeUnit unit = TimeUnit.SECONDS; BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10); ThreadFactory threadFactory = Executors.defaultThreadFactory(); ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); // 添加任务到线程池 for (int i = 0; i < 20; i++) { executor.execute(new Task(i)); } // 终止线程池 executor.shutdown(); } } class Task implements Runnable { private int taskId; public Task(int taskId) { this.taskId = taskId; } @Override public void run() { System.out.println("Task " + taskId + " is running."); } } ``` 在上面的示例中,我们创建了一个ThreadPoolExecutor对象executor,它使用corePoolSize=5、maximumPoolSize=10、keepAliveTime=1秒、单位TimeUnit.SECONDS的时间单位、workQueue容量为10的ArrayBlockingQueue以及默认的线程工厂。然后,我们向线程池中添加20个任务,每个任务都会打印任务的ID。最后,我们通过executor.shutdown()方法来终止线程池。 通过使用ThreadPoolExecutor类,我们可以方便地创建和管理线程池,从而实现任务的并发执行。 ### 回答3: Java中的ThreadPoolExecutor是一个用于创建和管理线程池的类。 首先,我们需要导入java.util.concurrent包中的ThreadPoolExecutor类。接下来,我们可以使用ThreadPoolExecutor的构造函数来创建一个线程池对象。构造函数接受一些参数,如核心线程数、最大线程数、线程等待时间等。 例如,我们可以使用以下代码创建一个线程池对象: ``` ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); ``` 在上面的代码中,我们创建了一个核心线程数为5,最大线程数为10的线程池。执行的任务将被放入一个无界队列LinkedBlockingQueue中,并且线程空闲时等待的时间为60秒。 接下来,我们可以通过调用execute()方法来提交任务给线程池执行。例如,我们可以创建一个实现了Runnable接口的任务,并将其提交给线程池执行,如下所示: ``` Runnable task = new MyTask(); executor.execute(task); ``` 上述代码中,MyTask是一个实现了Runnable接口的自定义任务类。我们创建了一个MyTask对象,并使用execute()方法将其提交给线程池执行。 最后,当不再需要使用线程池时,我们可以调用shutdown()方法来关闭线程池。例如: ``` executor.shutdown(); ``` 在上述代码中,executor.shutdown()方法将使线程池停止接受新的任务,并等待所有已提交的任务执行完成后,关闭线程池。 通过使用ThreadPoolExecutor类,我们可以方便地创建和管理线程池,提高多线程程序的性能和效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

折戏花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值