一、场景
在开发excel处理数据时,因为数据库的卡顿,一次插入2000条数据速度可能需要1min左右,所以考虑使用线程池;每200个分组,有n组,就开(n+1)个线程去分批同时处理这些数据。
二、依赖
1. pom.xml
<!--工具类hutool,java兵器库,用于读取excel-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.5.10</version>
</dependency>
2. excel的表格只有一个字段就是keyword,示例如下:

3. 数据库:t_keyword(只有一个字段keyword,并且加唯一索引)
三、代码

dao.java
package com.bds.pool.ihg_fb;
import org.nutz.dao.impl.NutDao;
import org.nutz.dao.impl.SimpleDataSource;
/**
* @ClassName: Dao.java
* @Description:
* @author : jack.Lu
* @version : V1.0
* @Date : 2019年7月11日 下午5:08:13
*/
public class Dao {
public static NutDao getDao() {
// 创建一个数据源
SimpleDataSource dataSource = new SimpleDataSource();
dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1/bds");
dataSource.setUsername("root");
dataSource.setPassword("root");
// 创建一个NutDao实例,在真实项目中, NutDao通常由ioc托管, 使用注入的方式获得.
NutDao dao = new NutDao(dataSource);
return dao;
}
}
dealExcel.java
package com.bds.pool.ihg_fb;
import java.util.ArrayList;
import java.util.List;
import org.nutz.dao.impl.NutDao;
/**
* @ClassName: DealExcel.java
* @Description:
* @author : jack.Lu
* @version : V1.0
* @Date : 2019年7月11日 下午2:18:48
*/
public class DealExcel implements Runnable{
List<String> list;
private String thread_name;
private Boolean success=false;
public DealExcel(String thread_name,List<String> list) {
this.thread_name = thread_name;
this.list=list;
}
public int deal() {
List<KeyWord> list_k = new ArrayList<>();
KeyWord k = new KeyWord();
NutDao dao = Dao.getDao();
for(String s : list) {
k.setKeyword(s);
try {
dao.insert(k);
} catch (Exception e) {
System.out.println(s+">>>>>>>>>>>已经插入!");
}
}
return list.size();
}
@Override
public void run() {
System.out.println(this.thread_name+"***********"+Thread.currentThread().getName()+"开始处理....");
int deal = this.deal();
success = true;
System.out.println(this.thread_name+"***********"+Thread.currentThread().getName()+"处理完成"+deal+"条数据");
}
public Boolean getSuccess() {
return success;
}
public String getThread_name() {
return thread_name;
}
}
KeyWord.java
package com.bds.pool.ihg_fb;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Table;
/**
* @ClassName: KeyWord.java
* @Description:
* @author : jack.Lu
* @version : V1.0
* @Date : 2019年7月11日 下午5:09:54
*/
@Table("t_keyword")
public class KeyWord {
@Column
private String keyword;
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
}
PoolThread.java
package com.bds.pool.ihg_fb;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import cn.hutool.core.io.FileUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
/**
* @ClassName: PoolThread.java
* @Description: 开启线程池
* @author : jack.Lu
* @version : V1.0
* @Date : 2019年7月11日 下午2:18:35
*/
public class PoolThread {
/**
*程序的入口
*/
public static void main(String args[])throws Exception{
readExcel();
}
/**
* 1.读取excel
* 2.对excel进行200分段
* 3.开启线程池
* @param args
*/
public static void readExcel(){
//1.读取excel
ExcelReader excelReader = ExcelUtil.getReader(FileUtil.file("C:\\Users\\admin\\Desktop\\新建文件夹\\XHS 笔记需求 0709-03.xlsx"));
List<Map<String,Object>> read = excelReader.readAll();
PoolThread pl = new PoolThread();
List<List<String>> excelByRead = pl.getExcelByRead(read);//500条数据,每200一条,共3组
//要开启的线程数//3组
int size = excelByRead.size();
ExecutorService pool = Executors.newFixedThreadPool(size+1);
List<DealExcel> task_list = new ArrayList<DealExcel>();
for (int i = 0; i < size; i++) {
List<String> list = excelByRead.get(i);
DealExcel dx = new DealExcel(i+"-",list);
task_list.add(dx);
pool.execute(dx);
}
//结束线程池
pool.shutdown();
while(true) {
if(pool.isTerminated()) {
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String s = "";
for(DealExcel d : task_list) {
s= s+d.getThread_name()+":"+(d.getSuccess()?"成功":"失败")+";";
}
System.out.println("----------------------------------------------");
System.out.println(s);
}
/**
* 以200为临界点 每200个放入一个String数组中,再放入List 集合中
* @param read
* @return
*/
private List<List<String>> getExcelByRead(List<Map<String,Object>> read) {
List<List<String>> list_list = new ArrayList<>();
int size = read.size();
int group = 200;
int num = size/group;
if(size%group!=0) {//说明不是整数101-》1+1=2
num = num +1;
}
System.out.println("准备创建几个数组就是开启多少线程:"+num);
//开始遍历excel
int temp = 0;
for (int j = 1; j <= num; j++) {
List<String> list = new ArrayList<>();
for (int i = temp; i < size; i++) {
Map<String, Object> map = read.get(i);
String keyword = map.get("keyword")+"";
list.add(keyword);
if ((i+1)%group==0) {
temp=i+1;
break;
}
}
System.out.println("*****已经加入集合"+j+"次");
list_list.add(list);
}
System.out.println("########################添加结束##################################");
return list_list;
}
}
学习总结:多种线程池的使用区别是他们的参数不同使用场景不同,在学习线程池的时候,到网上搜索所有的案例,但是发现全部都是分析线程池的区别,解剖源码,开始分析他们的体系,要么就是文章全部都是一样的东西,重复论述,巴拉巴拉。。。确实没有一个使用场景可以让好好参考,于是自己硬是想了一个场景,不知道效果如何但是确实联系了第一次写线程池来处理业务。希望有错可以给我及时指出来。谢谢!
