spring @Async 线程池使用
最近公司项目正逐渐从dubbo向springCloud转型,在本次新开发的需求中,全部使用springcloud进行,在使用时线程池,考虑使用spring封装的线程池,现将本次使用心得及内容记录下来
一、线程池常规使用方式
之前使用线程池的方式,都是自己定义线程池,然后写多线程类,用线程池去调用,如下:
package cn.leadeon.message.client; import cn.leadeon.comm.log.Log;
import cn.leadeon.message.req.MessageProducerReq;
import lombok.Data; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* 流量消息发送类,线程池调用
*
* @author LiJunJun
* @since 2018/9/30
*/
@Data
public class MessageClientSendMsg { /**
* 日志记录器
*/
private static final Log LOGGER = new Log(MessageClientSendMsg.class); /**
* 线程池
*/
private static ExecutorService threadPool; /**
* trace
*/
private String trace; /**
* 手机号
*/
private String cellNum; /**
* 消息实体
*/
private MessageProducerReq messageProducerReq; static {
threadPool = Executors.newFixedThreadPool(10);
} /**
* 构造函数
*
* @param trace 请求流水
* @param cellNum 电话号码
* @param messageProducerReq 消息实体
*/
public MessageClientSendMsg(String trace, String cellNum, MessageProducerReq messageProducerReq) { this.trace = trace;
this.cellNum = cellNum;
this.messageProducerReq = messageProducerReq;
} /**
* 消息发送
*/
public void sendMsg() { SendMsgRunable sendMsgRunable = new SendMsgRunable(); threadPool.execute(sendMsgRunable);
} /**
* 发送消息内部类并处理异常,不能影响主线程的业务
*/
class SendMsgRunable implements Runnable { @Override
public void run() { try {
MessageClientProducer msgClintProducer = new MessageClientProducer();
msgClintProducer.sendAsyncWithPartition(trace, cellNum, messageProducerReq);
} catch (Exception e) {
LOGGER.error("消息发送失败!,trace:" + trace);
}
}
}
}
二、使用spring的线程池
- 线程池的启用
有两种方式,配置文件或者注解
注解:使用@EnableAsync标注启用spring线程池,@Async将方法标注为异步方法,spring扫描到后,执行该方法时,会另起新线程去执行,非常简单
package cn.leadeon.message.test; import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component; /**
* @author LiJunJun
* @since 2018/10/11
*/
@Component
@EnableAsync
public class AsyncTest { @Async
public void test1() { System.out.println("异步执行test1!!!");
System.out.println("线程id:" + Thread.currentThread().getId());
System.out.println("线程名称:" + Thread.currentThread().getName()); } @Async
public void test2() { System.out.println("异步执行test2!!!");
System.out.println("线程id:" + Thread.currentThread().getId());
System.out.println("线程名称:" + Thread.currentThread().getName());
} @Async
public void test3() { System.out.println("异步执行test3!!!");
System.out.println("线程id:" + Thread.currentThread().getId());
System.out.println("线程名称:" + Thread.currentThread().getName());
}
}
配置文件:新增spring的配置文件spring-threadpool.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"
default-autowire="byName"> <description>流量消息spring线程池配置</description> <!-- 缺省的异步任务线程池 -->
<task:annotation-driven executor="messageExecutor"/>
<task:executor id="asyncExecutor" pool-size="100-10000" queue-capacity="10"/> <!-- 处理message的线程池 -->
<task:executor id="messageExecutor" pool-size="15-50" queue-capacity="100" keep-alive="60"
rejection-policy="CALLER_RUNS"/> </beans>
使用注解引入配置文件或者在自己的spring配置文件中import即可
package cn.leadeon.message.test; import org.springframework.context.annotation.ImportResource;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component; /**
* @author LiJunJun
* @since 2018/10/11
*/
@Component
@ImportResource("classpath:/config/spring-threadpool.xml")
public class AsyncTest { @Async
public void test1() { System.out.println("异步执行test1!!!");
System.out.println("线程id:" + Thread.currentThread().getId());
System.out.println("线程名称:" + Thread.currentThread().getName()); } @Async
public void test2() { System.out.println("异步执行test2!!!");
System.out.println("线程id:" + Thread.currentThread().getId());
System.out.println("线程名称:" + Thread.currentThread().getName());
} @Async
public void test3() { System.out.println("异步执行test3!!!");
System.out.println("线程id:" + Thread.currentThread().getId());
System.out.println("线程名称:" + Thread.currentThread().getName());
}
}
配置文件可以自己配置线程池的相关参数,自己可以配置多个线程池,使用时,用@Async(value="beanId")区分即可
注意点:
@EnableAsync注解与<task:annotation-driven executor="messageExecutor"/>等价,两者只能使用其一,不然启动会报错
- java编程方式配置自定义线程池,如下:
package cn.leadeon.message.base.threadpool; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor; /**
* 流量消息线程池配置
*
* @author LiJunJun
* @since 2018/10/10
*/
@Configuration
public class ThreadPoolConfiguration { /**
* 核心线程数:线程池创建时候初始化的线程数
*/
@Value("${executor.core.pool.size}")
private int corePoolSize; /**
* 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
*/
@Value("${executor.max.pool.size}")
private int maxPoolSize; /**
* 缓冲队列200:用来缓冲执行任务的队列
*/
@Value("${executor.queue.capacity}")
private int queueCapacity; /**
* 允许线程的空闲时间(单位:秒):当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
*/
@Value("${executor.keepalive.Seconds}")
private int keepAliveSeconds; /**
* 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
*/
@Value("${executor.thread.name.prefix}")
private String threadNamePrefix; @Bean
public Executor MessageExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveSeconds);
executor.setThreadNamePrefix(threadNamePrefix); // 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
- 测试
package cn.leadeon.message.test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; /**
* spring线程池单元测试
*
* @author LiJunJun
* @since 2018/10/11
*/
public class TestSpringThreadPool extends JunitTestBase { @Autowired
private AsyncTest asyncTest; /**
* spring线程池单元测试
*/
@Test
public void testThreadPool() { System.out.println("主线程id:" + Thread.currentThread().getId());
System.out.println("主线程名称:" + Thread.currentThread().getName());
asyncTest.test1();
asyncTest.test2();
asyncTest.test3(); }
}
测试结果:主线程和异步方法分别使用了不同的线程去调用,测试完成
spring @Async 线程池使用的更多相关文章
- Spring Boot 线程池
参考 SpringBoot 线程池 程序猿DD-Spring Boot使用@Async实现异步调用:自定义线程池 如何优雅的使用和理解线程池 Spring Boot线程池的使用心得 博客园-Sprin ...
- Spring集成线程池
自己在程序中手动New很容易造成线程滥用,创建线程也是比较消耗资源的操作,所以建议如果有此需求,将线程池统一交给Spring框架进行管理. 如下: <!--Spring 集成线程池,不允许自己开 ...
- spring boot: 线程池ThreadPoolTaskExecutor, 多线程
由于项目里需要用到线程池来提高处理速度,记录一下spring的taskExecutor执行器来实现线程池. ThreadPoolTaskExecutor的配置在网上找了很多解释没找到,看了下Threa ...
- Spring的线程池ThreadPoolTaskExecutor使用案例
1.Sping配置文件 <!-- 线程池配置 --> <bean id="threadPool" class="org.springframework. ...
- java多线程、线程池及Spring配置线程池详解
1.java中为什么要使用多线程使用多线程,可以把一些大任务分解成多个小任务来执行,多个小任务之间互不影像,同时进行,这样,充分利用了cpu资源.2.java中简单的实现多线程的方式 继承Thread ...
- spring 配置 线程池并使用 springtest 进行测试
在 applicationContext.xml 中配置spring线程池: <!-- 包路径扫描 --> <context:component-scan base-package= ...
- Spring中线程池的应用
多线程并发处理起来通常比较麻烦,如果你使用spring容器来管理业务bean,事情就好办了多了.spring封装了Java的多线程的实现,你只需要关注于并发事物的流程以及一些并发负载量等特性,具体来说 ...
- spring boot 线程池配置
1.配置类 package cn.com.bonc.util; import java.util.concurrent.Executor; import java.util.concurrent.Th ...
- spring定时任务.线程池,自定义多线程配置
定时任务及多线程配置xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=" ...
随机推荐
- 杂项-公司:联邦快递百科-un
ylbtech-杂项-公司:联邦快递百科 联邦快递( FedEx)是一家国际性速递集团,提供隔夜快递.地面快递.重型货物运送.文件复印及物流服务,总部设于美国田纳西州,隶属于美国联邦快递集团(FedE ...
- oracle里的查询转换
oracle里的查询转换的作用 Oracle里的查询转换,有称为查询改写,指oracle在执行目标sql时可能会做等价改写,目的是为了更高效的执行目标sql 在10g及其以后的版本中,oracle会对 ...
- Py修行路 python基础 (五)三元运算 字符编码 元组 集合 三级菜单优化!
三元运算 条件判断不能加冒号: a=3 b=5 c=a if a<b else b oct() 转成八进制的简写:16进制 标志:BH为后缀或是0x为前缀hex() 转成16进制 元组 跟列表是 ...
- Deep Learning 学习笔记(4):Logistic Regression 逻辑回归
逻辑回归主要用于解决分类问题,在现实中有更多的运用, 正常邮件or垃圾邮件 车or行人 涨价or不涨价 用我们EE的例子就是: 高电平or低电平 同时逻辑回归也是后面神经网络到深度学习的基础. (原来 ...
- 第七章 AOP(待续)
···············
- Windows nvidia显卡的设置方法
1.直接右下角打开N卡控制面板托盘按钮,一般来说都是自动隐藏在小箭头里的,点开就可以显示隐藏的图标了.[插入图片“右下角小箭头”]2.开始菜单 - 控制面板 ,可以看到“显卡控制面板”这个选项,进去就 ...
- java的IO流初探
DEMO代码: /* * 文件IO流的简单演示 */ package com.IO; import java.io.*; public class Demo_IO_1 { /** * @param a ...
- javascript中的垃圾回收
1引用计数垃圾回收 核心:跟踪记录对象被引用的次数.思路是如果一个对象A被赋值给了一个变量v,则该对象A的引用计数值加1,如果变量v又被赋予其他值了,比如a="str",则该对象A ...
- oracle 11g R2 标准版 64位linux安装
安装环境:Redhat es 5.5 64位 ,系统内存8G,swap 10G ,oracle 11G R2 标准版 一,Oracle 安装前的准备检查一下包,必须全部安装:binutils-2.17 ...
- requirejs——define——普通模块
一.普通模块可能包含的内容: 一个模块对应着一个js文件,由于模块可能包含着以下三种内容:模块名.依赖模块.返回给其他模块使用的参数:因此js文件根据包含内容的不同而写法不同. 一.传统的js脚本文件 ...