最近要做一个初始版的数据仓库项目,有一大批的MYSQL基础数据要通过整合后写入到ES,有部分数据量非常庞大,单线程批量写入会耗时很久,就想到了使用线程池来多线程做写入操作。
这个写法不要局限于我这个应用场景,别的应用场景也可以修改一下里面的逻辑。
java版本要求在 1.8以上
附代码:
import org.apache.commons.collections.CollectionUtils;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 批量多线程执行写入任务
*/
public class BatchThreadSave {
/**
* 批量多线程执行写入任务
* @param action 返回的截取数据表 自行写操作方法
* @param dataList 总数据表
* @param threadCount 需要的线程总数 0 < threadCount < 11
* @param <F> 指定数据表泛型
*/
public static <F> void save(Executor<? super List<F>> action, List<F> dataList, int threadCount) {
if (CollectionUtils.isEmpty(dataList)) {
return;
}
if (threadCount < 1 || threadCount > 10) {
return;
}
int threadSize = dataList.size() / (threadCount - 1);
// 总数据条数
int dataSize = dataList.size();
// 分段数
int threadNum = dataSize / threadSize + 1;
// 创建一个线程池
ExecutorService exec = Executors.newFixedThreadPool(threadCount);
// 定义一个任务集合
List<F> cutList = null;
// 确定每条线程的数据
try {
for (int i = 0; i < threadNum; i++) {
if (i == threadNum - 1) {
cutList = dataList.subList(threadSize * i, dataSize);
} else {
cutList = dataList.subList(threadSize * i, threadSize * (i + 1));
}
List<F> finalCutList = cutList;
exec.execute(() -> {
action.runAction(finalCutList);
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭线程池
exec.shutdown();
}
}
public interface Executor<T extends List> {
void runAction(T t);
}
}
那该怎么用呢?
public void buildUserIndex() {
List<User> users = userMapper.findAll();
log.info("共获取到用户:" + users.size());
BatchThreadSave.save(finalCutList -> {
int j = 0;
for (User user : finalCutList) {
j++;
log.info(Thread.currentThread().getName() + " 当前执行到" + user.getId() + " 剩余:" + (finalCutList.size() - j));
//finalCutList 这里就是被截取后的数据, 只管写后面的实现
//这里执行你的业务逻辑就行了 比如保存 数据处理等等
}
}, users, 10);
}