Spring中线程池的应用
多线程并发处理起来通常比较麻烦,如果你使用spring容器来管理业务bean,事情就好办了多了。spring封装了Java的多线程的实现,你只需要关注于并发事物的流程以及一些并发负载量等特性,具体来说如何使用spring来处理并发事务:
1.了解 TaskExecutor接口
Spring的TaskExecutor接口等同于java.util.concurrent.Executor接口。 实际上,它存在的主要原因是为了在使用线程池的时候,将对Java5的依赖抽象出来。 这个接口只有一个方法execute(Runnable task),它根据线程池的语义和配置,来接受一个执行任务。最初创建TaskExecutor是为了在需要时给其他Spring组件提供一个线程池的抽象。 例如ApplicationEventMulticaster组件、JMS的 AbstractMessageListenerContainer和对Quartz的整合都使用了TaskExecutor抽象来提供线程池。 当然,如果你的bean需要线程池行为,你也可以使用这个抽象层。
2. TaskExecutor接口的实现类
(1)SimpleAsyncTaskExecutor 类
这个实现不重用任何线程,或者说它每次调用都启动一个新线程。但是,它还是支持对并发总数设限,当超过线程并发总数限制时,阻塞新的调用,直到有位置被释放。如果你需要真正的池,请继续往下看。
(2)SyncTaskExecutor类
这个实现不会异步执行。相反,每次调用都在发起调用的线程中执行。它的主要用处是在不需要多线程的时候,比如简单的test case。
(3)ConcurrentTaskExecutor 类
这个实现是对Java 5 java.util.concurrent.Executor类的包装。有另一个备选, ThreadPoolTaskExecutor类,它暴露了Executor的配置参数作为bean属性。很少需要使用ConcurrentTaskExecutor, 但是如果ThreadPoolTaskExecutor不敷所需,ConcurrentTaskExecutor是另外一个备选。
(4)SimpleThreadPoolTaskExecutor 类
这个实现实际上是Quartz的SimpleThreadPool类的子类,它会监听Spring的生命周期回调。当你有线程池,需要在Quartz和非Quartz组件中共用时,这是它的典型用处。
(5)ThreadPoolTaskExecutor 类
它不支持任何对java.util.concurrent包的替换或者下行移植。Doug Lea和Dawid Kurzyniec对java.util.concurrent的实现都采用了不同的包结构,导致它们无法正确运行。 这个实现只能在Java 5环境中使用,但是却是这个环境中最常用的。它暴露的bean properties可以用来配置一个java.util.concurrent.ThreadPoolExecutor,把它包装到一个TaskExecutor中。如果你需要更加先进的类,比如ScheduledThreadPoolExecutor,我们建议你使用ConcurrentTaskExecutor来替代。
(6)TimerTaskExecutor类
这个实现使用一个TimerTask作为其背后的实现。它和SyncTaskExecutor的不同在于,方法调用是在一个独立的线程中进行的,虽然在那个线程中是同步的。
(7)WorkManagerTaskExecutor类
这个实现使用了CommonJ WorkManager作为其底层实现,是在Spring context中配置CommonJ WorkManager应用的最重要的类。和SimpleThreadPoolTaskExecutor类似,这个类实现了WorkManager接口,因此可以直接作为WorkManager使用。
3.线程池Demo之 ThreadPoolTaskExecutor
(1)编写测试类
- import org.springframework.core.task.TaskExecutor;
- public class MainExecutor {
- private TaskExecutor taskExecutor;
- public MainExecutor (TaskExecutor taskExecutor) {
- this.taskExecutor = taskExecutor;
- }
- public void printMessages() {
- for(int i = 0; i < 25; i++) {
- taskExecutor.execute(new MessagePrinterTask("Message" + i));
- }
- }
- private class MessagePrinterTask implements Runnable {
- private String message;
- public MessagePrinterTask(String message) {
- this.message = message;
- }
- public void run() {
- System.out.println(message);
- }
- }
- }
在业务代码中,通常以for循环的方式执行多个事务
for(int k = 0; k < n; k++) {
taskExecutor.execute(new ThreadTransCode());
}
其它繁琐的线程管理的事情就交给执行器去管理。
值得注意的事有两点
1, taskExecutor.execute(new ThreadTransCode()); 激活的线程都是守护线程,主线程结束,守护线程就会放弃执行,这个在业务中式符合逻辑的,在单元测试中为了看到执行效果,需要自行阻塞主线程。
2, taskExecutor.execute(new ThreadTransCode()); 的执行也不是完全安全的,在执行的过程中可能会因为需要的线程查过了线程队列的容量而抛出运行时异常,如有必要需要捕获。
(2)spring的配置
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "/spring-beans.dtd">
- <beans>
- <!-- 异步线程池 -->
- <bean id="threadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
- <!-- 核心线程数 -->
- <property name="corePoolSize" value="10" />
- <!-- 最大线程数 -->
- <property name="maxPoolSize" value="50" />
- <!-- 队列最大长度 >=mainExecutor.maxSize -->
- <property name="queueCapacity" value="1000" />
- <!-- 线程池维护线程所允许的空闲时间 -->
- <property name="keepAliveSeconds" value="300" />
- <!-- 线程池对拒绝任务(无线程可用)的处理策略 -->
- <property name="rejectedExecutionHandler">
- <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
- </property>
- </bean>
- <bean id="mainExecutor" class="supben.MainExecutor">
- <property name="threadPool" ref="threadPool" />
- </bean>
- <bean id="springScheduleExecutorTask" class="org.springframework.scheduling.concurrent.ScheduledExecutorTask">
- <property name="runnable" ref="mainExecutor" />
- <!-- 容器加载10秒后开始执行 -->
- <property name="delay" value="10000" />
- <!-- 每次任务间隔 5秒-->
- <property name="period" value="5000" />
- </bean>
- <bean id="springScheduledExecutorFactoryBean" class="org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean">
- <property name="scheduledExecutorTasks">
- <list>
- <ref bean="springScheduleExecutorTask" />
- </list>
- </property>
- </bean>
- </beans>
(3)调用
- ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
- MainExecutor te = (MainExecutor)appContext.getBean("taskExecutorExample");
- te.printMessages();
- System.out.println("11111111111111111111111");
(4)效果
案例:
@EnableScheduling
@Configuration
public class WebConfig extends SafWebMvcConfigurerAdapter { 、、、、 @Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
return executor;
} }
@Autowired
private TaskExecutor taskExecutor; void save2AllTenantSetting(final ForbidScope forbidScope) {
taskExecutor.execute(new Runnable() {
@Override
public void run() {
final List<Tenant> tenants = tenantService.findAll(); for (Tenant tenant : tenants) {
Runnable save2TenantSettingRunnable
= new Save2TenantSettingRunnable(tenant, forbidScope);
taskExecutor.execute(save2TenantSettingRunnable);
}
}
});
}
案例:
首先要将TaskExecutor加入spring容器进行管理
@Configuration
public class WebMvcConfigurerAdpter extends AbstractWebMvcConfigurerAdpter { @Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
WafJsonMapper.getMapper().enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);
} @Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize();
executor.setMaxPoolSize();
return executor;
} @Bean
public static PropertySourcesPlaceholderConfigurer propertyConfig() {
return new PropertySourcesPlaceholderConfigurer();
}
}
使用:
@RestController
@RequestMapping(value = "/v0.1/tasks")
public class TaskController { @Autowired
private TaskService taskService; @RequestMapping()
public Object execute() {
taskService.execute();
Map res = new HashMap();
res.put("result", "success");
return res;
}
}
@Service
public class TaskService { @Autowired
private TaskExecutor executor; public void execute() {
executor.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
System.out.println("task running ...");
} catch (Exception e) { }
}
}
});
}
}
每次调用/v0.1/tasks 接口时, 不用等到任务执行结束后才会响应,而是响应后,任务还可能在执行 -- 异步而非同步
Spring中线程池的应用的更多相关文章
- Spring中线程池的使用
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent ...
- Spring Boot 线程池
参考 SpringBoot 线程池 程序猿DD-Spring Boot使用@Async实现异步调用:自定义线程池 如何优雅的使用和理解线程池 Spring Boot线程池的使用心得 博客园-Sprin ...
- Java中java.util.concurrent包下的4中线程池代码示例
先来看下ThreadPool的类结构 其中红色框住的是常用的接口和类(图片来自:https://blog.csdn.net/panweiwei1994/article/details/78617117 ...
- Spring集成线程池
自己在程序中手动New很容易造成线程滥用,创建线程也是比较消耗资源的操作,所以建议如果有此需求,将线程池统一交给Spring框架进行管理. 如下: <!--Spring 集成线程池,不允许自己开 ...
- spring @Async 线程池使用
最近公司项目正逐渐从dubbo向springCloud转型,在本次新开发的需求中,全部使用springcloud进行,在使用时线程池,考虑使用spring封装的线程池,现将本次使用心得及内容记录下来 ...
- Java中线程池,你真的会用吗?
在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理. 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建 ...
- Java并发编程中线程池源码分析及使用
当Java处理高并发的时候,线程数量特别的多的时候,而且每个线程都是执行很短的时间就结束了,频繁创建线程和销毁线程需要占用很多系统的资源和时间,会降低系统的工作效率. 参考http://www.cnb ...
- 沉淀再出发:java中线程池解析
沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...
- Java中线程池,你真的会用吗?ExecutorService ThreadPoolExcutor
原文:https://www.hollischuang.com/archives/2888 在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及 ...
随机推荐
- Kubernetes 自动伸缩 auto-scaling
使用 Kubernetes 的客户能够迅速响应终端用户的请求,交付软件也比以往更快.但是,当你的服务增长速度比预期更快时,计算资源不够时,该怎么处理呢? 此时可以很自豪地说: Kubernetes 1 ...
- Last-Modified Header in Asp.net Core MVC
public class YourController : Controller { public ActionResult MyPage(string id) { var entity = _db. ...
- 【转】ProGuard的作用、使用及bug分析
原文地址:http://blog.csdn.net/forlong401/article/details/23539123. http://www.trinea.cn/android/proguard ...
- JS 浏览器对象
1.window对象 1.1 window对象 window对象是BOM的核心.window对象指当前的浏览器窗口 所有JavaScript全局对象 .函数以及变量均自动成为window对象的成员 全 ...
- 了解什么是版本控制 & 用tortoiseSVN 建立本地版本库来管理自己的代码
什么是版本控制 版本控制系统(Version Control System,简称VCS)广泛地应用于程序开发等领域,它可以协助你将某个指定的文件(甚至是一整个项目)返回至某个之前记录的状态,查看发生了 ...
- AI 的下一个重大挑战:理解语言的细微差别
简评:人类语言非常博大精妙,同一句话在不同的语境下,就有不同的含义.连人类有时候都不能辨别其中细微的差别,机器能吗?这就是人工智能的下一个巨大挑战:理解语言的细微差别.本文原作者是 Salesforc ...
- 利用python 学习数据分析 (学习三)
内容学习自: Python for Data Analysis, 2nd Edition 就是这本 纯英文学的很累,对不对取决于百度翻译了 前情提要: 各种方法贴: https://w ...
- php脚本cli 模式运行
参考文章 http://rapheal.sinaapp.com/2013/11/20/php_zend_hello_world/ http://www.douban.com/note/33788568 ...
- lnmp环境搭建错误集合
错误1: 页面显示:No input file specified nginx错误日志:FastCGI sent in stderr: "PHP message: PHP Warning: ...
- 解决Visual C++ Redistributable for Visual Studio 2015的安装问题(摘录)
1. Visual C++ Redistributable for Visual Studio 2015系统要求:Windows 7情况下必须是Windows 7 with SP1.或者Windows ...