当前位置:   article > 正文

利用线程池优化大批量数据库操作_使用java线程池优化for循环

使用java线程池优化for循环

在数据库中如果需要对大量的数据进行批量修改,并不是一项简单的工作。而利用线程池可以帮助我们解决这些问题

1.循环操作的代码

For循环插入5000条记录

  1. @Test
  2. void contextLoads6() {
  3. ArrayList<UserInfo> allUser = new ArrayList<>(5000);
  4. //生成size个UserInfo
  5. for (int i = 0; i < 5000; i++) {
  6. UserInfo userInfo = new UserInfo();
  7. userInfo.setId(String.valueOf(i + 10000));
  8. allUser.add(userInfo);
  9. }
  10. long startTime = System.currentTimeMillis();
  11. for (int i = 0;i<5000;i++){
  12. mapper.insert(allUser.get(i));
  13. }
  14. System.out.println("单线程for循环插入5000耗时:"+(System.currentTimeMillis()-startTime));
  15. }

 

耗时:14944ms

 

2.利用多线程

实现Callable接口

  1. public class InsertTarget implements Callable<Integer> {
  2. private UserInfoMapper mapper;
  3. private List<UserInfo> list;
  4. private CountDownLatch countDownLatch;
  5. public InsertTarget(UserInfoMapper mapper, List<UserInfo> list, CountDownLatch countDownLatch) {
  6. this.mapper = mapper;
  7. this.list = list;
  8. this.countDownLatch = countDownLatch;
  9. }
  10. @Override
  11. public Integer call() throws Exception {
  12. //记录插入成功的条数
  13. int rows = 0;
  14. for (UserInfo user :
  15. list) {
  16. mapper.insert(user);
  17. rows++;
  18. }
  19. //完全插入成功,CountDownLatch-1
  20. if (rows == list.size()) {
  21. countDownLatch.countDown();
  22. }
  23. return rows;
  24. }
  25. }

 

Service层:

  1. /**
  2. * Copyright (C), 2017-2022, 湖南兴盛优选电子商务有限公司.
  3. *
  4. * @author 13240
  5. * @description 针对表【user_info】的数据库操作Service实现
  6. * @createDate 2022-07-27 10:39:08
  7. */
  8. @Slf4j
  9. @Service
  10. public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
  11. implements UserInfoService {
  12. @Autowired
  13. UserInfoMapper mapper;
  14. @Override
  15. public Integer insertList(Integer size) {
  16. //制造数据,list里面有size(5000)个UserInfo
  17. List<UserInfo> allUser = this.createSizeList(size);
  18. //线程数
  19. int threadSize = ?;
  20. ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(threadSize, threadSize, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
  21. //每个线程处理的数据量
  22. final Integer dataPartionLength = (allUser.size() + (threadSize) - 1) / (threadSize);
  23. int downLatchSize = 0;
  24. //将downLatchSize这个值计算出来
  25. if (size%dataPartionLength==0){
  26. downLatchSize=size/dataPartionLength;
  27. }else {
  28. downLatchSize=size/dataPartionLength+1;
  29. }
  30. CountDownLatch latch = new CountDownLatch(downLatchSize);
  31. long startTime = System.currentTimeMillis();
  32. for (int i = 0; i < downLatchSize; i++) {
  33. //每个线程均分需要处理的数据
  34. List<UserInfo> threadDatas = allUser.stream()
  35. .skip(i * dataPartionLength).limit(dataPartionLength).collect(Collectors.toList());
  36. //调用实现了Callable的InsertTarget类,并将mapper,threadDatas,latch传进去
  37. InsertTarget insertTarget = new InsertTarget(mapper, threadDatas, latch);
  38. FutureTask<Integer> futureTask = new FutureTask<>(insertTarget);
  39. //执行任务
  40. threadPoolExecutor.execute(futureTask);
  41. }
  42. try {
  43. //保证每个线程完成后再完成计时
  44. latch.await();
  45. long endTime = System.currentTimeMillis();
  46. log.info("线程数为{}的线程池插入5000用时:{}",threadSize, endTime - startTime);
  47. } catch (InterruptedException e) {
  48. e.printStackTrace();
  49. }
  50. return 200;
  51. }
  52. /**
  53. * 用来生成数据,返回一个size大小的list
  54. */
  55. private List<UserInfo> createSizeList(Integer size) {
  56. ArrayList<UserInfo> list = new ArrayList<>(100);
  57. //生成size个UserInfo,并放进List
  58. for (int i = 0; i < size; i++) {
  59. UserInfo userInfo = new UserInfo();
  60. userInfo.setId(String.valueOf(i + 1));
  61. list.add(userInfo);
  62. }
  63. return list;
  64. }
  65. }

 

耗时:

多线程提交修改时,尝试了不同线程数对插入速度的影响,具体可以看下面表格

核心线程数

1

4

5

10

15

耗时63273847303652304630

结论:

多线程对数据库进行操作时,并非线程数越多操作越快。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/793547
推荐阅读
相关标签
  

闽ICP备14008679号