前言:最近项目中与融360项目中接口对接,有反馈接口(也就是我们接收到请求,需要立即响应,并且还要有一个接口推送给他们其他计算结果),推送过程耗时、或者说两个接口不能是同时返回,有先后顺序。
这时我想到了把自己Controller立即返回接受成功,中间添加一个新的线程去做其他耗时的操作(线程池配置和参数测试讲解请阅读第5步)。
1、Controller代码如下:
@Autowired private CallThreadDemo worker;
@RequestMapping("/bandBankConfirm2") public void bandBankConfirm2(String jsonString) {
System.out.println("controller开始--------------");
//这里是需要调用第三方的接口传入参数
String method = "is.api.v3.order.bindcardfeedback";
Map<String, Object> map = new HashMap<>();
map.put("order_no", "254986512848973");
map.put("bind_status", 1);
map.put("reason", "");
//这里开始调用线程池的方法
worker.callRong360(method, map);
System.out.println("controller end --------------"); //renderJson这个方法是jfinal的,可以理解为@ReponseBody 需要return的操作了
renderJson("接口调用完毕"); }
2、调用线程池的方法
@Componentpublic class CallThreadDemo {
@Autowired private ThreadPoolTaskExecutor executor;
@Autowired private ServiceTest serviceTest; public void callRong360(final String method, final Map<String, Object> map) { //这个类是我封装的抽象类,里面有一个公共方法,具体代码下面有
ServiceParent callRong360Method = new ServiceParent() {
@Override public void run() { try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程开始-------------");
//这里调用第三方公用接口
JSONObject result = callBandBankMethod(method, map);
//这里调用service方法,实现自己的业务逻辑
serviceTest.insertUser("111", "222222");
System.out.println(result);
System.out.println("线程结束-------------");
}
};
executor.execute(callRong360Method);
System.out.println("当前活动线程数:"+ executor.getActiveCount());
System.out.println("核心线程数:"+ executor.getCorePoolSize());
System.out.println("总线程数:"+ executor.getPoolSize());
System.out.println("最大线程池数量"+executor.getMaxPoolSize());
System.out.println("线程处理队列长度"+executor.getThreadPoolExecutor().getQueue().size());
}3、封装的抽象类代码如下:
public abstract class ServiceParent implements Runnable { public JSONObject callBandBankMethod(String method, Map<String, Object> map) {
//这个方法是调用三方的接口,公用部分 // //输入 参数如下 :// Map<String, Object> map = new HashMap<>();// map.put("order_no", "254986512848973");// map.put("bind_status", 1);// map.put("reason", "");// net.sf.json.JSONObject ret = callRong360Method.callBandBankMethod("is.api.v3.order.bindcardfeedback", map);//// // 异常情况输出参数 为 null:
OpenapiClient openapiClient = new OpenapiClient();
openapiClient.setMethod(method); for (Map.Entry<String, Object> entry : map.entrySet()) {
openapiClient.setField(entry.getKey(), String.valueOf(entry.getValue()));
}
net.sf.json.JSONObject ret = null; try {
ret = openapiClient.execute();
} catch (Exception e) {
e.printStackTrace();
System.out.println("调用反馈接口异常---->" + e.getMessage());
} return ret;
}
//这里定义为抽象方法,创建匿名内部类或者继承类必须实现 public abstract void run();4、ServiceTest接口方法如下:
@Servicepublic class ServiceTest {
@Autowired private BankMapper bankMapper;
@Transactional(rollbackFor = {Exception.class}) public void insertUser(String s, String s1) {
bankMapper.insertUser(s, s1); //这里创建异常,测试事务。已测试,事务生效
int i = 1 / 0;
}
}以上四步,成功在调用Controller方法立即返回结果,也实现了另外的一个线程去调用三方接口返回信息,并且实现了自己的业务逻辑。
5、接着我们继续说明一下线程池对应配置和参数说明,这里我们通过测试来说明参数的作用(corePoolSize 核心线程数量,maxPoolSize 最大线程数,queueCapacity 处理队列)
threadpool.corePoolSize=5 threadpool.keepAliveSeconds=200 threadpool.maxPoolSize=10 threadpool.queueCapacity=2
<!-- 线程池 -->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="${threadpool.corePoolSize}" />
<property name="keepAliveSeconds" value="${threadpool.keepAliveSeconds}" />
<property name="maxPoolSize" value="${threadpool.maxPoolSize}" />
<property name="queueCapacity" value="${threadpool.queueCapacity}" />
</bean>
<!--请在bean xsd中配置task-->
<task:annotation-driven executor="taskExecutor" />
下面贴出测试输出的日志信息:controller开始--------------
queueCapacity=2
controller开始--------------当前活动线程数:5核心线程数:5总线程数:5最大线程池数量10 线程处理队列长度2 ---------------》继续放入队列中,达到了最大队列数量2 controller end --------------
controller开始--------------当前活动线程数:6-----------------》这里因为达到了最大队列数量,所以继续创建线程去执行,一直到最后到最大线程数量核心线程数:5总线程数:6最大线程池数量10 线程处理队列长度2 controller end --------------
controller开始--------------当前活动线程数:7核心线程数:5总线程数:7最大线程池数量10 线程处理队列长度2 controller end --------------
controller开始--------------当前活动线程数:8核心线程数:5总线程数:8最大线程池数量10 线程处理队列长度2 controller end --------------
controller开始--------------当前活动线程数:9核心线程数:5总线程数:9最大线程池数量10 线程处理队列长度2 controller end --------------
controller开始--------------当前活动线程数:10 --------------》这里活动线程数量达到了最大线程池数量核心线程数:5总线程数:10最大线程池数量10 线程处理队列长度2 controller end --------------
controller开始-------------- 2018-07-01 20:23:19 -----------------》这里继续调用,因为最大线程池数量和队列中都已经到了最大值,抛出了异常 [] [] [WARN]-[Thread: qtp1276504061-60]-[org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logException()]: Handler execution resulted in exception org.springframework.core.task.TaskRejectedException: Executor [java.util.concurrent.ThreadPoolExecutor@17d95b77[Running, pool size = 10, active threads = 10, queued tasks = 2, completed tasks = 0]] did not accept task: com.fastx.cooperate.rong360.rong.service.CallThreadDemo$1@5fa6bf1 at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.execute(ThreadPoolTaskExecutor.java:245) at com.fastx.cooperate.rong360.rong.service.CallThreadDemo.callRong360(CallThreadDemo.java:43)
这样,通过输出的日志,我们可以很容易的理解了各个参数的作用。
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
