当前位置:网站首页>ThreadPoolExecutor 从精通到入门
ThreadPoolExecutor 从精通到入门
2022-06-09 11:23:00 【扶朕去网吧】
ThreadPoolExecutor 是 java.util.concurrent 包下的一个类,在jdk1.5版本引入,帮助开发人员管理线程并方便地执行并行任务。
通俗来说,ThreadPoolExecutor 的作用是生产和管理线程池的,可以通过调用其 execute 方法和 submit 方法执行多线程任务。
ThreadPoolExecutor 使用
创建执行器
ExecutorService 对象和 ThreadPoolExecutor 的关系如下图:

ExecutorServiceConfig:
package com.ramble.threadpool.config;import java.util.concurrent.*;
public class ExecutorServiceConfig {
/**
* 定义一个并发任务执行器服务
*/
private static ExecutorService executorService;
/**
* 在类加载的时候初始化并发任务执行器
*/
static {
init();
}
/**
* 防止类属性被篡改
*/
private ExecutorServiceConfig() {
}
/**
* 初始化并发任务执行器。核心线程数量:设置为2,初始创建的线程池大小;最大线程数量:设置为3;空闲线程存活时间:设置为3秒,当非核心线程执行完任务之后,若没有新的任务分派,存活多久后自动销毁;任务队列:设置为2,当线程池创建的线程数量达到最大线程数量后,新进来的任务会排队等候;
* 拒绝策略:设置为直接抛异常
* <p>
* 以上配置需要根据:实际的业务场景、项目实际情况、实际硬件情况等各种因素综合考量
*/
private static void init() {
executorService = new ThreadPoolExecutor(2, 3, 3, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(2), new ThreadPoolExecutor.AbortPolicy());
}
/**
* 获取默认并发任务执行器
*
* @return
*/
public static ExecutorService getDefaultExecutor() {
return executorService;
}
/**
* 获取固定大小并发任务执行器
*
* @return
*/
public static ExecutorService getFixedExecutor() {
return Executors.newFixedThreadPool(10);
}
/**
* 获取其他并发任务执行器
* @return
*/
public static ExecutorService getOtherExecutor() {
//todo
return null;
}
}
这个类的核心目的是构造一个 ExecutorService , 供业务代码调用。当业务代码需要创建线程执行任务的时候,不用创建、管理和维护“执行者(线程)”,只需要告诉 ExecutorService 需要做什么 “事情(任务)”。
ExecutorService 对象必须是单例的,因为此对象本身是管理线程池的,如果自己都不是线程安全的,那使用起来将有可能发生灾难。
一个java进程允许创建多个ExecutorService 。根据业务实际情况,如果业务逻辑比较单一,大概率创建一种就满足使用。若业务繁杂,可根据业务特性抽象出多种类型以满足不同需求。譬如代码中就创建了两个 getDefaultExecutor 和 getFixedExecutor
关于线程池配置,如核心线程数量、最大线程数量、拒绝策略等等没有绝对正确的值做参考,需要根据实际情况设定
创建任务
- 通过实现 Runnable 接口并重写 run 方法创建无返回值的多线程任务
- 通过实现 Callable 接口并重写 call 方法创建有返回值的多线程任务
Task1:
package com.ramble.threadpool.task;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Task1 implements Runnable {
/**
* 新线程执行一个任务,没有参数,不需要返回值,此任务和其他任务没有先后顺序
*/
@Override
public void run() {
try {
Thread.sleep(3000L);
log.info("TaskOne,thread is ={},thread name is={}", Thread.currentThread().getId(), Thread.currentThread().getName());
throw new IllegalAccessException("主动抛一个异常");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Task2:
package com.ramble.threadpool.task;
import com.alibaba.fastjson.JSON;
import com.ramble.threadpool.dto.TaskTwoParam;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Task2 implements Runnable {
private TaskTwoParam param;
public Task2(TaskTwoParam param) {
this.param = param;
}
/**
* 新线程执行一个任务,参数通过构造函数传递,不需要返回值,此任务和其他任务没有先后顺序
*/
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("TaskTwo,thread id is ={},thread name is={}, param is ={}", Thread.currentThread().getId(), Thread.currentThread().getName(), JSON.toJSONString(param));
}
}
Task3:
package com.ramble.threadpool.task;
import com.alibaba.fastjson.JSON;
import com.ramble.threadpool.dto.TaskDto;
import com.ramble.threadpool.dto.TaskTwoParam;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
@Slf4j
public class Task3 implements Callable {
private TaskTwoParam param;
public Task3(TaskTwoParam param) {
this.param = param;
}
/**
* 新线程执行一个任务,通过构造函数传递参数,有返回值,此任务和其他任务没有先后顺序
*
* @return
* @throws Exception
*/
@Override
public Object call() throws Exception {
log.info("Task3,thread id is ={},thread name is={}, param is ={}", Thread.currentThread().getId(), Thread.currentThread().getName(), JSON.toJSONString(param));
return new TaskDto().setName("task3-callable");
}
}
Task4:
package com.ramble.threadpool.task;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Task4 implements Runnable {
/**
* 新线程执行一个任务,没有参数,不需要返回值,此任务和其他任务没有先后顺序
*/
@Override
public void run() {
try {
Thread.sleep(3000L);
log.info("Task4,thread is ={},thread name is={}", Thread.currentThread().getId(), Thread.currentThread().getName());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
执行任务
在 controller 中模拟发起多线程任务。
package com.ramble.threadpool.controller;
import com.alibaba.fastjson.JSON;
import com.ramble.threadpool.config.ExecutorServiceConfig;
import com.ramble.threadpool.dto.TaskDto;
import com.ramble.threadpool.dto.TaskTwoParam;
import com.ramble.threadpool.task.Task1;
import com.ramble.threadpool.task.Task2;
import com.ramble.threadpool.task.Task3;
import com.ramble.threadpool.task.Task4;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@GetMapping("/task")
public String testTask() {
log.info("testTask,thread is ={},thread name is={}", Thread.currentThread().getId(), Thread.currentThread().getName());
// for (int i = 0; i < 4; i++) {
// ExecutorServiceConfig.getExecutor().execute(new Task1());
// }
//
// for (int i = 0; i < 5; i++) {
// ExecutorServiceConfig.getExecutor().execute(new Task2(new TaskTwoParam().setId(100).setName("cnaylor")));
// }
ExecutorServiceConfig.getDefaultExecutor().execute(new Task1());
ExecutorServiceConfig.getDefaultExecutor().execute(new Task2(new TaskTwoParam().setId(100).setName("cnaylor")));
ExecutorServiceConfig.getFixedExecutor().execute(new Task4());
Future<TaskDto> taskResult = ExecutorServiceConfig.getDefaultExecutor().submit(new Task3(new TaskTwoParam().setId(100).setName("cnaylor")));
TaskDto taskDto;
try {
taskDto = taskResult.get();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
return "testTask";
}
ThreadPoolExecutor 拒绝策略
所谓拒绝策略,一般是指当前线程池处于满负荷状态,所有的线程都有正在处理的任务,阻塞队列也排满了的情况下,对新进来的任务做出何种响应。
默认的拒绝策略有四种,同时也可以自定义拒绝策略。
- AbortPolicy
- CallerRunsPolicy
- DiscardOldestPolicy
- DiscardPolicy
AbortPolicy
抛一个异常(RejectedExecutionException),此任务将无法执行。
CallerRunsPolicy
线程池满载了, 此任务将由调用发起线程来执行。比如我们在一个http请求线程中调用了线程池处理异步任务,但是现在线程池满了,那么此任务将转由http请求 线程处理。缺点是会导致http请求线程阻塞,达不到异步处理的效果。优点是任务会正常执行,避免被任务执行器丢弃。
DiscardOldestPolicy
在阻塞队列最前端抛弃一个任务,然后将此任务添加到阻塞队列中排队。最前端是指最先添加到阻塞队列的任务。
DiscardPolicy
当前任务不会执行,也不会抛异常,好像什么也没有发生一样。
自定义拒绝策略
自己编写一个类,实现 RejectedExecutionHandler 接口,并重写 rejectedExecution 方法即可实现自定义拒绝策略。需要在实例化 ThreadPoolExecutor 的时候,将自定义策略配置进去。
边栏推荐
- Windows远程时提示CredSSP加密数据库修正
- 系统集成项目管理工程师考试说明
- H3C certified cloud computing Engineer
- 7.移除元素
- From these papers in 2022, we can see the trend of recommended system sequence modeling
- Win10 your organization has turned off automatic update. How to solve the problem?
- 06 | the first step of China Taiwan landing: enterprise strategy decomposition and current situation research (Discovery)
- 7.<tag-回溯和子集问题>lt.70.子集 + lt.90.子集 II
- What is the difference between a fire engineer and a fireman?
- Preparation guide for 2022 soft test information security engineer examination
猜你喜欢
![[data center stage] 00 opening words data center stage, is it a trap? Or the golden key?](/img/19/256cdcf783986d1012ddc75c8b2c31.png)
[data center stage] 00 opening words data center stage, is it a trap? Or the golden key?

Explain the basic knowledge of copper clad PCB
![[转载] 分布式系统的“脑裂”到底是个什么玩意?](/img/7a/de7df9830f589be0b2214f875eb95e.png)
[转载] 分布式系统的“脑裂”到底是个什么玩意?

Win11正式发布新功能

15 Win32 class library name in WMI

5.<tag-回溯和切割问题>lt.93.复原IP地址

Wsl2 environment setup

SIGIR 2022 | CMI:结合对比学习和多兴趣挖掘的微视频推荐

12.<tag-二叉树和BST基础>lt.701. 二叉搜索树中的插入操作 dbc

消防工程师与消防员有什么区别?
随机推荐
01 | 来龙去脉:中台为什么这么火?
tag回溯-刷题预备知识-1. 回溯法模板, + lt.46. 全排列
06 | the first step of China Taiwan landing: enterprise strategy decomposition and current situation research (Discovery)
[data center stage] 00 opening words data center stage, is it a trap? Or the golden key?
小米智能摄像机云台Pro如何插入视频监控存储卡
【转载】搞懂G1垃圾收集器
H3C认证安全技术高级工程师
马斯克 “取消交易”威胁奏效 推特同意开放数据库供其核查
10.<tag-二叉树和BST基础>lt.700. 二叉搜索树中的搜索 + lt.98. 验证二叉搜索树 + lt.530. 二叉搜索树的最小绝对差(同lt.783)
5. bracket generation
Do you dare to deliver your microservices independently?
HEVC之HM学习02
Computer quick index query software listary
H3C Certified Wireless Internet expert
系统集成项目管理工程师考试说明
H3C certified routing switching network senior engineer
中国科学院院刊 | 包云岗:加速发展关键核心技术,必须把握技术发展的自身规律
Focus on DNS: analysis of ISC bind
Go zero micro Service Practice Series (II. Service splitting)
09 | 中台落地第四步:中台的建设与接入(Delivery)