使用 线程池 ThreadPoolTaskExecutor 上传文件

使用线程池

工作中如果需要开启多线程处理任务,可使用线程池来实现,在springboot中,可预先配置一个线程池使用,放到上下文中,也可以新创建一个,然后设置参数。

如下面所示,其中核心线程数和最大线程数可根据计算机核数来定,我这里只是举个例子

     // 核心线程池大小
    private int corePoolSize = 50;

    // 最大可创建的线程数
    private int maxPoolSize = 200;

    // 队列最大长度
    private int queueCapacity = 1000;

    // 线程池维护线程所允许的空闲时间
    private int keepAliveSeconds = 300;  

	@Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(maxPoolSize);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

使用时:

@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;

public void uploadFiles(Map<String, SysUser> map, List<SysUser> userSaveList,List<File> fileSaveList) throws Exception {
        if (CollectionUtils.isEmpty(fileSaveList)) {
            return;
        }
        CountDownLatch latch = new CountDownLatch(fileSaveList.size());
        log.info("开始进行任务处理——开启多线程处理,核心线程:{} ,最大线程:{} !", threadPoolTaskExecutor.getCorePoolSize(),threadPoolTaskExecutor.getMaxPoolSize());
        for (File file : fileSaveList) {
            String fileNameOnly = file.getName();
            String name = fileNameOnly.substring(fileNameOnly.lastIndexOf("/") + 1, fileNameOnly.lastIndexOf("."));
            SysUser userUpdate = map.get(name);
            SysUser sysUserSave = new SysUser();
            sysUserSave.setUserId(userUpdate.getUserId());
            sysUserSave.setUserType(userUpdate.getUserType());
            //上传文件
            String suffix = file.getName().substring(file.getName().lastIndexOf("."));
            FileInputStream inputStream = new FileInputStream(file);
            threadPoolTaskExecutor.execute(()->{
                try {
                    String path = FileUploadUtils.upload(Constants.MINIO_PCBFILE_BUCKET, "avatar/" + sysUserSave.getUserType() + "/" + fileNameOnly, inputStream, ContentType.getContentType(suffix.toLowerCase()));
                    inputStream.close();
                    sysUserSave.setAvatar(path);
                    userSaveList.add(sysUserSave);
                    latch.countDown();
                    int j = fileSaveList.size() / 10;
                    if (latch.getCount() % (j) == 0) {
                        log.info("处理度:{} %",latch.getCount() / (j)*10);
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        }
        latch.await();
        log.info("所有任务都完成!");
    }
//处理完之后
   log.info("-------------- 总共花费 {} s ,成功更新 {} 个头像--------------", Duration.between(start, end).getSeconds(), userSaveList.size());

其中 CountDownLatch时是为了实现线程同步,所有上传文件线程跑完了之后才执行主线程!类似于操作系统pv操作

CountDownLatch(int count); //构造方法,创建一个值为count 的计数器。
await();//阻塞当前线程,将当前线程加入阻塞队列。
await(long timeout, TimeUnit unit);//在timeout的时间之内阻塞当前线程,时间一过则当前线程可以执行,
countDown();//对计数器进行递减1操作,当计数器递减至0时,当前线程会去唤醒阻塞队列里的所有线程。

关于核心线程数

网传核心线程数标准为

根据当前业务是IO密集型还是CPU密集型,设置核心线程数

CPU密集型:核心线程数 = CPU核数 + 1

IO密集型:核心线程数 = CPU核数 * 2

但我电脑是6核,核心线程数设置为12时上传700个文件用了39秒,设置为50时用了19秒,然后核心线程数目为100时,耗费17s。好像跟这个差距有点大。所以也不知道这个标准对不对了。

//核心线程数为12
 - -------------- 总共花费 39 s ,成功更新 698 个头像--------------
//核心线程数为50
 - -------------- 总共花费 19 s ,成功更新 698 个头像--------------
//核心线程数为100    
- -------------- 总共花费 17 s ,成功更新 698 个头像--------------
  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值