本文主要是介绍Java 使用线程池和CountDownLatch分批插入或者更新数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
需求:在开发业务报表时,需要从MySQL数据库读取数据后进行操作,然后写入数据库,使用定时任务跑批。
分析:①兼顾性能,② MySQL没有Oracle那么方便、强大的存储过程。综上所述,使用线程池以分批提交的方案把数据插入MySQL数据库,对于更新操作、在Java端进行分页等的操作,本方案也支持。代码如下:
/*** 分页操作数据*/
@Slf4j
@Component
public class BatchDealDemo {private void batchDeal(List data, int batchNum) throws InterruptedException {int totalNum = data.size();int pageNum = totalNum % batchNum == 0 ? totalNum / batchNum : totalNum / batchNum + 1;ExecutorService executor = Executors.newFixedThreadPool(pageNum);log.info("主线程开始执行 begin --- ");try {CountDownLatch countDownLatch = new CountDownLatch(pageNum);List subData = null;int fromIndex, toIndex;for (int i = 0; i < pageNum; i++) {fromIndex = i * batchNum;toIndex = Math.min(totalNum, fromIndex + batchNum);subData = data.subList(fromIndex, toIndex);ImportTask task = new ImportTask(subData, countDownLatch);executor.execute(task);}// 当前线程必须在执行完任务之后立即调用CountDownLatch.await()方法,// 这样主线程的操作就会被阻塞,直到全部子线程完成各自的任务。// CountDownLatch类中计数器的值等于0时,主线程就能通过await()方法恢复执行自己的任务。countDownLatch.await();log.info("数据操作完成!可以在此开始主线程的其它业务");log.info("主线程执行完毕 end --- ");} finally {// 关闭线程池,释放资源executor.shutdown();}}class ImportTask implements Runnable {private List list;private CountDownLatch countDownLatch;public ImportTask(List data, CountDownLatch countDownLatch) {this.list = data;this.countDownLatch = countDownLatch;}@Overridepublic void run() {if (null != list) {// 业务逻辑,例如批量insert或者updatelog.info("现在操作的数据是{}", list);}// 发出子线程任务完成的信号countDownLatch.countDown();}}
}
这篇关于Java 使用线程池和CountDownLatch分批插入或者更新数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!