007-多线程-JUC线程池-Spring线程池配置、池子如何配置参数
一、概述
Spring通过ThreadPoolTaskExecutor实现线程池技术,它是使用jdk中的Java.util.concurrent.ThreadPoolExecutor进行实现。
1.1、xml方式配置
<!-- Spring线程池 -->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数 -->
<property name="corePoolSize" value="5" />
<!-- 线程池维护线程的最大数量 -->
<property name="maxPoolSize" value="10" />
<!-- 允许的空闲时间, 默认60秒 -->
<property name="keepAliveSeconds" value="60" />
<!-- 任务队列 -->
<property name="queueCapacity" value="50" />
<!-- 线程超过空闲时间限制,均会退出直到线程数量为0 -->
<property name="allowCoreThreadTimeOut" value="true"/>
<!-- 对拒绝task的处理策略 -->
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy" />
</property>
</bean>
java代码
//帮我们创建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定创建容器时使用哪个配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringThreadPoolExecutorTest { @Autowired
private ThreadPoolTaskExecutor taskExecutor; @Test
public void newFixedThreadPoolTestSubmit() throws Exception {
List<Future<?>> list=new ArrayList<>();
for (int i = 0; i < 20; i++) {
Future<?> submit = taskExecutor.submit(new DataTask("ssss" + i));
list.add(submit);
}
for (Future<?> future : list) {
future.get();
}
} class DataTask implements Runnable {
private String a; public DataTask(String a) {
this.a = a;
} @Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-------"+ LocalDateTime.now()+a);
}
}
}
输出
-------2019-08-06T21:23:18.105ssss0
-------2019-08-06T21:23:18.105ssss3
-------2019-08-06T21:23:18.105ssss1
-------2019-08-06T21:23:18.105ssss2
-------2019-08-06T21:23:18.105ssss4
-------2019-08-06T21:23:19.110ssss8
-------2019-08-06T21:23:19.110ssss6
-------2019-08-06T21:23:19.110ssss5
-------2019-08-06T21:23:19.110ssss7
-------2019-08-06T21:23:19.110ssss9
-------2019-08-06T21:23:20.113ssss10
-------2019-08-06T21:23:20.113ssss12
-------2019-08-06T21:23:20.113ssss13
-------2019-08-06T21:23:20.113ssss11
-------2019-08-06T21:23:20.113ssss14
-------2019-08-06T21:23:21.117ssss18
-------2019-08-06T21:23:21.117ssss16
-------2019-08-06T21:23:21.117ssss17
-------2019-08-06T21:23:21.117ssss15
-------2019-08-06T21:23:21.117ssss19
可以看到每5个一组一组的运行,
过程:corePoolSize→queueCapacity→开启maxPoolSize
当一个新任务来临时:
1)如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务;
2)如果此时线程池中的数量等于corePoolSize,但是缓冲队列workQueue未满,那么任务被放入缓冲队列;
3)如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maxPoolSize,建新的线程来处理被添加的任务;
4)如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maxPoolSize,那么通过handler所指定的策略来处理此任务;
5)当线程池中的线程数量大于corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止,如果allowCoreThreadTimeOut为false,则线程数量维持在corePoolSize, 如果为true,则线程数量可最低降至0;
1.2、使用task:executor方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"> <!-- 包路径扫描 -->
<context:component-scan base-package="spring.task"/> <!-- 定义线程池 -->
<task:executor id="executor" pool-size="5" queue-capacity="10" rejection-policy="DISCARD_OLDEST"/> </beans>
java 测试
@Component
public class AsyncTask { @Autowired
private ThreadPoolTaskExecutor executor; @PostConstruct
public void testAsycTask() {
for (int i = 0; i < 10; i++) {
executor.execute(new Runnable() {
public void run() {
asyncTask();
}
});
}
} private void asyncTask(){
System.out.println( "---" + Thread.currentThread().getName());
}
}
二、池子如何配置参数
2.1、默认值
corePoolSize=1
queueCapacity=Integer.MAX_VALUE
maxPoolSize=Integer.MAX_VALUE
keepAliveTime=60s
allowCoreThreadTimeout=false
rejectedExecutionHandler=AbortPolicy()
2.2、如何设置
需要根据几个值来决定
- tasks :每秒的任务数,假设为100~1000
- taskcost:每个任务花费时间,假设为0.1s
- responsetime:系统允许容忍的最大响应时间,假设为2s
配置计算
- corePoolSize = 每秒需要多少个线程处理?
* threadcount = tasks/(1/taskcost) =tasks*taskcout = (100~1000)*0.1 = 10~100 个线程。corePoolSize设置应该大于10
* 根据8020原则,如果80%的每秒任务数小于200,那么corePoolSize设置为20即可
- queueCapacity = (coreSizePool/taskcost)*responsetime
* 计算可得 queueCapacity = 20/0.1*2 = 400。意思是队列里的线程可以等待4s,超过了的需要新开线程来执行
* 切记不能写:LinkedBlockingQueue queue = new LinkedBlockingQueue(); 实际是设置为Integer.MAX_VALUE,这样队列会很大,线程数只会保持在corePoolSize大小,当任务陡增时,不能新开线程来执行,响应时间会随之陡增。
- maxPoolSize = (max(tasks)- queueCapacity)/(1/taskcost)
* 计算可得 maxPoolSize = (1000-400)/10 = 60
* (最大任务数-队列容量)/每个线程每秒处理能力 = 最大线程数
- rejectedExecutionHandler:根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理
- keepAliveTime和allowCoreThreadTimeout采用默认通常能满足
以上都是理想值,实际情况下要根据机器性能来决定。如果在未达到最大线程数的情况机器cpu load已经满了,则需要通过升级硬件和优化代码,降低taskcost来处理。
xml
007-多线程-JUC线程池-Spring线程池配置、池子如何配置参数的更多相关文章
- Java多线程系列 JUC线程池04 线程池原理解析(三)
转载 http://www.cnblogs.com/skywang12345/p/3509954.html https://blog.csdn.net/qq_22929803/article/det ...
- Java多线程系列 JUC线程池07 线程池原理解析(六)
关闭“线程池” shutdown()的源码如下: public void shutdown() { final ReentrantLock mainLock = this.mainLock; // ...
- Java多线程系列 JUC线程池03 线程池原理解析(二)
转载 http://www.cnblogs.com/skywang12345/p/3509954.html http://www.cnblogs.com/skywang12345/p/351294 ...
- Java多线程系列 JUC线程池02 线程池原理解析(一)
转载 http://www.cnblogs.com/skywang12345/p/3509960.html ; http://www.cnblogs.com/skywang12345/p/35099 ...
- Java多线程系列 JUC线程池01 线程池框架
转载 http://www.cnblogs.com/skywang12345/p/3509903.html 为什么引入Executor线程池框架 new Thread()的缺点 1. 每次new T ...
- Spring线程池开发实战
Spring线程池开发实战 作者:chszs,转载需注明. 作者博客主页:http://blog.csdn.net/chszs 本文提供了三个Spring多线程开发的例子,由浅入深,由于例子一目了然, ...
- Java多线程学习(八)线程池与Executor 框架
目录 历史优质文章推荐: 目录: 一 使用线程池的好处 二 Executor 框架 2.1 简介 2.2 Executor 框架结构(主要由三大部分组成) 2.3 Executor 框架的使用示意图 ...
- Spring线程池ThreadPoolTaskExecutor配置及详情
Spring线程池ThreadPoolTaskExecutor配置及详情 1. ThreadPoolTaskExecutor配置 <!-- spring thread pool executor ...
- spring线程池ThreadPoolTaskExecutor与阻塞队列BlockingQueue
一: ThreadPoolTaskExecutor是一个spring的线程池技术,查看代码可以看到这样一个字段: private ThreadPoolExecutor threadPoolExecut ...
随机推荐
- Java精通并发-notify方法详解及线程获取锁的方式分析
wait(): 在上一次https://www.cnblogs.com/webor2006/p/11404521.html中对于无参数的wait()方法的javadoc进行了解读,而它是调用了一个参数 ...
- :Spring-06 -AOP [面向切面编程] -配置异常通知的两种方式--AspectJ 方式 -Schema-based 方式
三.配置异常通知的步骤(AspectJ 方式) 1.只有当切点报异常才能触发异常通知 2.在spring 中有AspectJ 方式提供了异常通知的办法 3.实现步骤: 3.1新建类,在类写任意名称的方 ...
- docker 进程 转载:
今天我们会分析Docker中进程管理的一些细节,并介绍一些常见问题的解决方法和注意事项. 容器的PID namespace(名空间) 在Docker中,进程管理的基础就是Linux内核中的PID名空间 ...
- LightOJ - 1323 - Billiard Balls(模拟)
链接: https://vjudge.net/problem/LightOJ-1323 题意: You are given a rectangular billiard board, L and W ...
- Backpack IV
Description Given an integer array nums[] which contains n unique positive numbers, num[i] indicate ...
- grep命令选项
-c:只输出匹配行的计数. -I:不区分大 小写(只适用于单字符). -h:查询多文件时不显示文件名. -l:查询多文件时只输出包含匹配字符的文件名. -n:显示匹配行及 行号. -s:不显示不存在或 ...
- MySQL 必会知识
一.为什么用自增列作为主键 1.如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引. 如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为 ...
- 第三节.vue.js属性与方法
1. <!DOCTYPE html><html><head><meta charset="UTF-8"><title>I ...
- Ubuntu下彻底卸载默认安装的mysql,自己手动下载安装MYSQL
彻底卸载: sudo apt-get autoremove --purge mysql-server-5.7 sudo apt-get remove mysql-common sudo rm -rf ...
- C语言中一个字符对应一个ascii码;占一个1个字节8个二进制位;存到内存中也是用ascii的十进制的二进制表示
/** 只读变量和常量 const 只读 const int a; int const a;//同上面的代码行是等价的,都表示一个常整形数. int *const a;//const具有"左 ...