线程池在springboot项目中的实际应用

使用多线程能够让单行的程序并行执行,大大提高程序效率,比如实际项目中,不同的系统之间的数据同步,或是财务系统中大量的交易数据的对账处理等,应用线程池可以大大缩短程序执行时间。首先在应用多线程之前应尽量的了解线程池的运行原理及参数的意义。

以下案例是模拟商品数据同步,假如有两个系统 商品管理系统(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;

}

以上就是线程池的简单应用,具体业务逻辑,可根据需求完善程序。

Spring Boot创建线程池也有多种方式,其一种常用的方式是通过配置文件来创建。 首先,在Spring Boot应用程序的配置文件添加以下配置: ``` spring: task: execution: pool: core-size: 10 max-size: 20 queue-capacity: 200 ``` 上述配置创建了一个线程池,其包含10个核心线程,最多可以有20个线程,队列容量为200。这些值可以根据您的实际需求进行设置。 然后,在需要使用线程池的地方,可以使用Spring框架提供的TaskExecutor接口来使用线程池。例如: ``` import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.task.TaskExecutor; import org.springframework.stereotype.Component; @Component public class MyService { @Autowired private TaskExecutor taskExecutor; public void myMethod() { taskExecutor.execute(new Runnable() { public void run() { // 需要异步执行的代码逻辑 } }); } } ``` 在上面的示例代码,MyService类的myMethod()方法使用了TaskExecutor接口来执行异步任务。在实际应用,可以根据需要使用不同的TaskExecutor实现类来创建不同的线程池。 除了通过配置文件来创建线程池,还可以在Java代码手动创建线程池。例如: ``` import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.springframework.stereotype.Component; @Component public class MyService { private ExecutorService executorService = Executors.newFixedThreadPool(10); public void myMethod() { executorService.submit(new Runnable() { public void run() { // 需要异步执行的代码逻辑 } }); } } ``` 在上面的示例代码,MyService类的myMethod()方法手动创建了一个包含10个线程的线程池,并使用submit()方法来执行异步任务。 希望这个回答能够对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值