多线程实战项目笔记

项目内源码

/**
* 业务 EasyExcel解析了1百万条数据到了一个 list里面 所以 这个方法使用了多线程分段处理数据
* 多线程指的是 创建了线城池 分段指的是根据最大线程数算出来的每个新的newList应该分有多少数据
*/
public void dataProcess() throws InterruptedException {
        int count = 50000;      //一个线程处理10000条数据
        count = list.size() < 20 ? 1 : list.size() / 20;
        int listSize = list.size();        //数据集合大小
        int runSize = (listSize / count) + 1;  //开启的线程数
        List<ModelWjJysjImport> newlist = null;       //存放每个线程的执行数据
        ExecutorService executor = Executors.newFixedThreadPool(runSize);      //创建一个线程池,数量和开启线程的数量一样
        //创建两个个计数器
        CountDownLatch begin = new CountDownLatch(1);
        CountDownLatch end = new CountDownLatch(runSize);
        //循环创建线程
        for (int i = 0; i < runSize; i++) {
            //计算每个线程执行的数据
            if ((i + 1) == runSize) {
                int startIndex = (i * count);
                int endIndex = list.size();
                newlist = list.subList(startIndex, endIndex);
            } else {
                int startIndex = (i * count);
                int endIndex = (i + 1) * count;
                newlist = list.subList(startIndex, endIndex);
            }
            //线程类 todo这里的 线程类 就是主要的处理逻辑的地方
            MyThreadWJ mytheadWJ = new MyThreadWJ(newlist, begin, end, modelWjJysjService);
            //这里执行线程的方式是调用线程池里的executor.execute(mythead)方法。

            executor.execute(mytheadWJ);
        }

        begin.countDown();
        end.await();

        //执行完关闭线程池
        executor.shutdown();
    }
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.CountDownLatch;

@Slf4j
public class MyThreadWJ implements Runnable {

    private List<ModelWjJysjImport> list;
    private CountDownLatch begin;
    private CountDownLatch end;
    private ModelWjJysjService modelWjJysjService;

    public MyThreadWJ(List<ModelWjJysjImport> list,CountDownLatch begin,CountDownLatch end,ModelWjJysjService modelWjJysjService){
        this.list = list;
        this.begin = begin;
        this.end = end;
        this.modelWjJysjService = modelWjJysjService;
    }


    @Override
    public void run()  {
        try {
            for (ModelWjJysjImport dataBO : list) {
                // 这里做的是新增的逻辑 引用了一些其他的方法 处理特殊数据 与线程无关所以
//删除了 这里主要还是展示线程方法处理的整体
                ModelWjJysj dataDO = new ModelWjJysj();
                BeanUtils.copyProperties(dataBO, dataDO);
                dataDO.setCsrq(returnTime(dataBO.getCsrq()));
                dataDO.setSfzh(processSfzh(dataBO.getSfzh()));
                dataDO.setJzTime(processLocalDateTime(dataBO.getJzTime()));
                dataDO.setCreateTime(LocalDateTime.now());
                dataDO.setDelFlag(Boolean.FALSE);
                dataDO.setAge(getAge(dataBO.getSfzh()));
                modelWjJysjService.insertSelective(dataDO);
            }
            // 等待
            begin.await();
        }catch (Exception e){
            log.error("线程执行错误");
            log.error(e.getMessage());
        }finally {
            end.countDown();
        }
    }

   
}

项目后自己综合整理 想法

/**
*这里是创建了测试方法 和 内部类 测试 线程池
* 这个线程池 只创建了一个计数器 所以执行完方法后测试方法的线程关闭 方法执行结束
*/
//TODO 情况一 只创建一个计数器
@Test
    public void tst(){
        //创建了一个线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        try {
            // 创建了一个计数器
            CountDownLatch count1 = new CountDownLatch(1);
            tests test = new tests(count1);
            for (int i = 1;i <= 3;i++) {
                executor.execute(test);
            }
            count1.await();
            executor.shutdown();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }finally {
            executor.shutdown();
        };
    }
}
class tests implements Runnable{

    private  CountDownLatch  count1;

    public tests (CountDownLatch count1){
        this.count1 = count1;
    }

    @Override
    public void run() {
        try {
            for (int i = 0;i < 10;i++){
                System.out.println(Thread.currentThread().getId()+"---"+i+"---循环中");
                Thread.sleep(1000);
            }
            count1.countDown();
            System.out.println("主线在执行");
        }catch (Exception e){
            System.out.println(e.getMessage());
        }finally{
          
        }
    }
}
/**
* 但是结合情况二 的反应多出了几个疑问 有懂行大哥欢迎评论解答谢谢
* 疑问就是 创建了两个计数器的方法 在测试信息打印完成之后 线程池好像进入了等待状态方法主体虽然
* 走完 但是方法还在一直消耗资源 猜测是线程池没有关闭资源 所以为什么项目中实战却用了两个计数器的方式
*/
//TODO情况二 创建两个计数器
@Test
    public void tst(){
        //创建了一个线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        try {
            // 创建了一个计数器
            CountDownLatch count1 = new CountDownLatch(1);
            // 创建了一个计数器
            CountDownLatch count2 = new CountDownLatch(11);
            tests test = new tests(count1,count2);
            for (int i = 1;i <= 3;i++) {
                executor.execute(test);
            }
            count1.countDown();
            count2.await();
            executor.shutdown();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }finally {
            executor.shutdown();
        };
    }
}
class tests implements Runnable{

    private  CountDownLatch  count1;
    private  CountDownLatch  count2;

    public tests (CountDownLatch count1,CountDownLatch count2){
        this.count1 = count1;
        this.count2 = count2;
    }

    @Override
    public void run() {
        try {
            for (int i = 0;i < 10;i++){
                System.out.println(Thread.currentThread().getId()+"---"+i+"---循环中");
                Thread.sleep(1000);
            }
            count1.countDown();
            System.out.println("主线在执行");
        }catch (Exception e){
            System.out.println(e.getMessage());
        }finally{
            count2.countDown();
        }
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值