项目内源码
/**
* 业务 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();
}
}
}