前两天有个需求:调用第三方接口,这个接口的响应时间有点长,需要5~7秒的响应,而且只能一条一条报文发送,实时返回结果,同步请求。
所遇到的问题:需要发送的数据量特别大的时候,响应时间可能需要好几十个小时,这个明显是不能接受的。
方案:初次遇到这样的问题,没有那么丰富的经验和解决方案,能想到的就是启动多线程来解决这个问题。
下边贴出我实现的关键代码和步骤,欢迎大家发表看法和提出更好的方案。
首先是配置文件,我用的是spring的线程池,因为对方接口支持的最大并发数200,所以我设置maxPoolSize的值为200,这个值可以根据实际并发来定
在加一点 我的数据库最大连接数配的50,需要注意的是如果连接数配的小,执行并发是就会报错提示数据库连接数已超
<!-- spring多线程 -->
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数 -->
<property name="corePoolSize" value="100" />
<!-- 最大线程数 -->
<property name="maxPoolSize" value="200" />
<!-- 队列最大长度 >=mainExecutor.maxSize -->
<property name="queueCapacity" value="2500" />
<!-- 线程池维护线程所允许的空闲时间 -->
<property name="keepAliveSeconds" value="300" />
<!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃. -->
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
配置文件就上边一个,下边就是实现类MultiThread 需要实现Runnable接口
public class MultiThread implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(MultiThread.class);
private IFlowPrizeService flowPrizeService;//调用其它业务层逻辑需要这么引用 private List<Map<String,Object> listnew;
private int starNum = 0; //分页 起始数
private JSONObject json = null;
public MultiThread() {
}
public MultiThread(IFlowPrizeService flowPrizeService, List<Map<String,Object> listnew) {
this.flowPrizeService = flowPrizeService;
this.listnew= listnew;
}
@Override
public void run() {//执行方法
threadPrize(flowPrizeService,listnew);//具体实现
}}
调用
int starNum = 0;
for (int i = 0; i <= listnew.size() / 10000; i++) {//listnew需要处理的总数据量 10000是每个线程处理的最大数据量
taskExecutor.execute(new MultiThreadNew(iFlowPrizeService,getList(listnew, 10000, starNum)));//getList是按每10000切分listnew
starNum += Integer.valueOf(flowPrizeThread);
}私有方法 对总记录listnew切分
private List<Map<String,Object> getList(List<Map<String,Object> listnew,
int flowPrizeThread, int starNum) {
int end = starNum + flowPrizeThread;
if (end >= listnew.size()) {
end = listnew.size();
}
return listnew.subList(starNum, end);//subList用法 /** List接口有一个实例方法List<E> subList(int fromIndex, int toIndex),其作用是返回一个以fromIndex为起始索引(包含),以toIndex为终止索引(不包含)的子列表(List)。
但值得注意的是,返回的这个子列表的幕后其实还是原列表;也就是说,修改这个子列表,将导致原列表也发生改变;反之亦然。 **/
}