• 使用ThreadPoolExecutor线程池实现并发操作并返回结果


    在日常业务开发中,有时对一些没有关联的业务操作,如查询多个结果,使用串行调用并不是一个理想的处理方式,可以优化为使用线程池做并发调用,这样在一定程度上能提高性能,如下测试demo方法,使用TimeUnit.SECONDS.sleep(xxx)模拟业务处理时长:

    public static String getName () throws Exception {
            TimeUnit.SECONDS.sleep(5);
    
            return "阿三";
        }
    
        public static int getAge () throws Exception {
            TimeUnit.SECONDS.sleep(15);
    
            return 18;
        }
    
        public static String getBirthday () throws Exception {
            TimeUnit.SECONDS.sleep(8);
    
            return "1001";
        }

    1.串行调用耗时测试

      // 1、串行测试
      StopWatch watch = new StopWatch();
      watch.start("串行");
      String name = getName();
      int age = getAge();
      String birthday = getBirthday();
      watch.stop();
      System.out.println(name + "-" + age + "-" + birthday + ", 串行 耗时:" + watch.getTotalTimeMillis());

    2.并行耗时测试

      2.1 使用ThreadPoolExecutor的submit方法,参数为Callable类型的可以有返回值

    public <T> Future<T> submit(Callable<T> task) 
        /**
         * 使用线程池
         */
        static ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 20, 2000L,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>());
    
        public static void main(String[] args) throws Exception {
    
            
            // 2.并行测试1
            StopWatch watch2 = new StopWatch();
            watch2.start("并行");
            // 此方式get方法阻塞了后面的服务,用法不对
            String submit = poolExecutor.submit(() -> getName()).get();
            Integer submit1 = poolExecutor.submit(() -> getAge()).get();
            String submit2 = poolExecutor.submit(() -> getBirthday()).get();
            watch2.stop();
            System.out.println(submit + "-" + submit1 + "-" + submit2  + ", 并行1 耗时:" + watch2.getTotalTimeMillis());
    
            // 3.并行测试2
            StopWatch watch3 = new StopWatch();
            watch3.start("并行2");
            Future<String> future = poolExecutor.submit(() -> getName());
            Future<Integer> future1 = poolExecutor.submit(() -> getAge());
            Future<String> future2 = poolExecutor.submit(() -> getBirthday());
            String submit3 = future.get();
            Integer submit4 = future1.get();
            String submit5 = future2.get();
            watch3.stop();
            System.out.println(submit3 + "-" + submit4 + "-" + submit5 + ", 并行3 耗时:" + watch3.getTotalTimeMillis());
    
        }

      2.2 对返回值为统一类型的可以使用invokeAll方法:

    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
            // 4.并行测试3
            StopWatch watch4 = new StopWatch();
            watch4.start("并行3");
            Callable<String> taskName = () -> getName();
            Callable<String> taskBirthday = () -> getBirthday();
            List<Callable<String>> taskList = Lists.newArrayList();
            taskList.add(taskName);
            taskList.add(taskBirthday);
            List<Future<String>> futures = poolExecutor.invokeAll(taskList);
    
            StringBuilder sb = new StringBuilder();
            for (Future<String> resultFuture : futures) {
                sb.append(resultFuture.get()).append("-");
            }
            watch4.stop();
            System.out.println(sb.toString() + ", 并行3 耗时:" + watch4.getTotalTimeMillis());    

    3.测试结果

    可以看出最后两种方式耗时和最大耗时服务的用时差不多


    Github源码参照

  • 相关阅读:
    029- 位运算符
    028- 三目运算符
    027- 字符串链接运算符
    026- 布尔运算符
    lucene 结合数据库做搜索
    JDK 1.8判断集合种的元素是否存在相同
    Springboot 集成jpa使用
    json 的使用 Java对象转json
    Java 短信发送
    1 eclipse 离线安装activiti插件
  • 原文地址:https://www.cnblogs.com/kingsonfu/p/13036963.html
Copyright © 2020-2023  润新知