账号密码登录
微信安全登录
微信扫描二维码登录

登录后绑定QQ、微信即可实现信息互通

手机验证码登录
找回密码返回
邮箱找回 手机找回
注册账号返回
其他登录方式
分享
  • 收藏
    X
    java中list.spliterator以及多线程使用问题
    48
    0

    问题描述

    小弟在公司的项目中使用了list.spliterator()方法尝试将一个List<Map<String, Object>>对象按照一定的条件查询数据库,然后将查询的结果(是一个List对象)通过map.put()放进这个map中,但是通过线程池创建线程并执行后第一次会查询到正确结果,但是后面重复请求就没有put进去的集合了
    小弟刚进入编程界不久对并发安全问题以及其它问题都还不熟悉,请各位大佬解答一下

    问题出现的环境背景及自己尝试过哪些方法

    我把Map<String, Object>换成了List<ConcurrentHashMap<String, Object>>也不行,我以为是list的问题,所以用了Collections.synchronizedList(list);

    相关代码

        //这是controller
        public List<ConcurrentHashMap<String,Object>> test(@RequestBody List<ConcurrentHashMap<String,Object>> list){
            final List<ConcurrentHashMap<String, Object>> concurrentHashMaps = Collections.synchronizedList(list);
            List<ConcurrentHashMap<String, Object>> ListMap = calculateService.getListMap(concurrentHashMaps);
            return ListMap;
        }
        
        //这是service
        // 线程池我设置了线程数为4 并且countDownLatch也为4
         public List<ConcurrentHashMap<String, Object>> getListMap(List<ConcurrentHashMap<String, Object>> list) {
            // 将list四等分
            Spliterator<ConcurrentHashMap<String, Object>> allList = list.spliterator();
            Spliterator<ConcurrentHashMap<String, Object>> halfList = allList.trySplit();
            Spliterator<ConcurrentHashMap<String, Object>> quarterAllList = allList.trySplit();
            Spliterator<ConcurrentHashMap<String, Object>> quarterHalfList = halfList.trySplit();
    
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            RequestContextHolder.setRequestAttributes(servletRequestAttributes,true);
            //将分好的List放进线程池
            List<Spliterator<ConcurrentHashMap<String, Object>>> spliterators = Arrays.asList(allList, halfList, quarterAllList, quarterHalfList);
            for (Spliterator<ConcurrentHashMap<String, Object>> spliterator : spliterators) {
                if (ObjectUtil.isNotNull(spliterator)){
                    executor.execute(new SelectTask(taxInfoMapper,countDownLatch,spliterator));
                }
            }
            try {
                // 阻塞住主线程,等待任务完成
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            return list;
        }
    
    
        public class SelectTask implements Runnable {
            private TaxInfoMapper taxInfoMapper;
            private CountDownLatch countDownLatch;
            private Spliterator<ConcurrentHashMap<String, Object>> list;
    
            public SelectTask(TaxInfoMapper taxInfoMapper, CountDownLatch countDownLatch, Spliterator<ConcurrentHashMap<String, Object>> list) {
                this.taxInfoMapper = taxInfoMapper;
                this.countDownLatch = countDownLatch;
                this.list = list;
            }
    
            @Override
            public void run() {
                list.forEachRemaining(map -> {
                    String taxNo = (String) map.get("taxNo");
                    String deptNo = (String) map.get("deptNo");
                    String month = (String) map.get("month");
                    List<String> idList = (List<String>) map.get("idList");
                    // 这里我传进来一个mapper然后查询出一个对象List
                    List<TaxInfoBO> taxInfoBOS = taxInfoMapper.selectTaxInfoList(taxNo, deptNo, month, idList);
                    // 然后将他放在原先的map中
                    map.put("taxInfoList",taxInfoBOS);
                    countDownLatch.countDown();
                });
            }
        }

    你期待的结果是什么?

    这是我的那个请求参数之一

        {
            "taxNo": "123124",
            "month": "2019-12",
            "deptNo": "1",
            "idList":[
                "310104198603042438",
                "130130198907243027",
                "330722199110014512",
                "362322198903110046",
                "330402198703161239",
                "33062119820508869X",
                "33262419880810002X",
                "371002199204038253"
    
            ]
        },
        
        
       返回结果应该有一个taxInfoList
    3
    打赏
    收藏
    点击回答
    您的回答被采纳后将获得:提问者悬赏的 10 元积分
        全部回答
    • 0
    • 头头碰着黑 普通会员 1楼

      在Java中,List接口提供了一种遍历集合的容器,其中包含一个可迭代对象(如List<T>)和一个可调用方法next(),用于获取并返回当前迭代的下一个元素。List.spliterator()方法用于获取并返回列表的可迭代对象的迭代器,这个迭代器会遍历列表的所有元素,但不会创建一个新的列表,而是返回一个实现了Spliterator接口的对象,该对象可以在多线程环境中并发地访问列表的所有元素。

      以下是一个简单的示例,展示如何在多线程环境中使用List.spliterator()方法:

      ```java import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger;

      public class MultiThreadedListSpliteratorExample { public static void main(String[] args) { // 创建一个包含10个元素的列表 List list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); list.add(6); list.add(7); list.add(8); list.add(9); list.add(10);

          // 创建一个线程池,包含5个线程
          ExecutorService executor = Executors.newFixedThreadPool(5);
      
          // 创建一个计数器,用于记录当前线程访问的元素数量
          AtomicInteger count = new AtomicInteger(0);
      
          // 使用spliterator()方法获取列表的可迭代对象的迭代器
          List<Integer> iterator = list.spliterator();
      
          // 创建一个线程池的执行器,每个线程负责访问一个元素并更新计数器
          for (int i = 0; i < 5; i++) {
              executor.execute(() -> {
                  // 获取当前迭代的下一个元素
                  int element = iterator.next();
      
                  // 更新计数器
                  count.incrementAndGet();
      
                  // 在这里执行一些操作,如打印元素或执行其他耗时操作
                  System.out.println("Element " + element + " accessed, count: " + count.get());
              });
          }
      
          // 关闭线程池
          executor.shutdown();
      
          // 等待所有线程完成
          while (!executor.isTerminated()) {
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      
          // 打印所有的元素和计数器
          System.out.println("Elements accessed: " + list.size() + ", count: " + count.get());
      }
      

      } ```

      在这个示例中,我们首先创建了一个包含10个整数的List。然后,我们创建了一个线程池,包含5个线程,每个线程负责访问一个元素并更新计数器。我们使用List.spliterator()方法获取列表的可迭代对象的迭代器,并将它赋值给iterator变量。然后,我们创建了一个线程池的执行器,每个线程负责访问一个元素并更新计数器。在每个线程中,我们首先获取当前迭代的下一个元素,然后更新计数器,并在System.out.println()方法中打印出元素和计数器的值。

      最后,我们关闭线程池,并等待所有线程完成。我们打印出所有的元素和计数器,以验证程序的行为。在多线程环境中,由于List.spliterator()方法返回的是一个Spliterator对象,所以可以同时执行多个线程,每个线程都可以独立地访问列表中的元素,而不会阻塞其他线程。然而,由于线程安全的限制,不能在多线程环境中直接修改列表,所以要处理这种情况,通常需要使用一些同步机制,如LockConcurrentHashMap,以确保在多个线程同时访问列表时的线程安全性。

    更多回答
    网站公告
    扫一扫访问手机版
    • 回到顶部
    • 回到顶部