使用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源碼參照


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM