使用多线程能够让单行的程序并行执行,大大提高程序效率,比如实际项目中,不同的系统之间的数据同步,或是财务系统中大量的交易数据的对账处理等,应用线程池可以大大缩短程序执行时间。首先在应用多线程之前应尽量的了解线程池的运行原理及参数的意义。
以下案例是模拟商品数据同步,假如有两个系统 商品管理系统(A)和 商城系统(B),现B 需要把A系统添加的商品信息一次性同步过来,现只模拟A系统的发送逻辑。
一、定义线程池配置
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
@Slf4j
public class ThreadPoolConfig {
@Bean("asyncServiceExecutor")
public ThreadPoolTaskExecutor asyncServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(8);
// 最大线程数
executor.setMaxPoolSize(8);
// 线程池的队列大小
executor.setQueueCapacity(1000);
// 线程名称前缀
executor.setThreadNamePrefix("async-service-");
// 当线程池饱和拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
二、编写同步接口 GoodsController.java
import com.siji.sys.common.CommonResult;
import com.siji.sys.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
private GoodsService goodsService;
/**
* 每次同步的条数
*/
private static final int threshold = 1000;
/**
* 商品同步接口
*
* @return
*/
@PostMapping("synGoodsInfo")
public CommonResult synGoodsInfo() {
//查询数据库,获取商品信息总数
int total = goodsService.getGoodsTotal();
//一次发送1000条,计算出分几段发出
int segmentNum = total / threshold;
for (int i = 0; i < segmentNum; i++) {
int offset = i * 1000;
goodsService.sendGoodsData(offset, threshold);
}
return CommonResult.SUCCESS();
}
}
三、编写同步逻辑 GoodsServiceImpl.java,并且使用线程池执行同步任务,即@Async("asyncServiceExecutor")
import com.alibaba.fastjson.JSON;
import com.siji.sys.entity.Goods;
import com.siji.sys.mapper.GoodsMapper;
import com.siji.sys.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Service
public class GoodsServiceImpl implements GoodsService {
@Autowired
private GoodsMapper goodsMapper;
/**
* 使用asyncServiceExecutor线程池来执行发送数据
*
* @param offset
* @param len
*/
@Override
@Async("asyncServiceExecutor")
public void sendGoodsData(int offset, int len) {
Map map = new HashMap<>();
map.put("offset", offset);
map.put("len", len);
// 分页查询,每次查1000条
List<Goods> goodsList = goodsMapper.getGoodsList(map);
//此处模拟循环逐一发送商品数据(根据需求可为成批量发送),如果同步失败,可以将失败的信息记录下来
for (Goods goods : goodsList) {
try {
// 假设每条数据需要1s
TimeUnit.MILLISECONDS.sleep(500);
System.out.println(Thread.currentThread().getName() + "开始同步商品数据:" + JSON.toJSONString(goods));
// 如果同步失败,可以将失败的信息记录下来,做补偿
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 获取商品总数量
*/
@Override
public int getGoodsTotal() {
return goodsMapper.getGoodsTotal();
}
}
四、编写GoodsMapper.java
import com.siji.sys.entity.Goods;
import java.util.List;
import java.util.Map;
public interface GoodsMapper {
List<Goods> getGoodsList(Map map);
int getGoodsTotal();
}
五、编写mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.siji.sys.mapper.GoodsMapper">
<select id="getGoodsList" resultType="goods">
select * from Goods limit #{offset},#{len}
</select>
<select id="getGoodsTotal" resultType="int">
select count(*) from Goods
</select>
</mapper>
六、编写实体类,Goods.java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Goods {
private Integer id;
/**
* 商品名称
*/
private String name;
/**
* 商品单价
*/
private BigDecimal price;
/**
* 商品类型
*/
private String type;
}
以上就是线程池的简单应用,具体业务逻辑,可根据需求完善程序。