在日常業務開發中,有時對一些沒有關聯的業務操作,如查詢多個結果,使用串行調用並不是一個理想的處理方式,可以優化為使用線程池做並發調用,這樣在一定程度上能提高性能,如下測試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.測試結果
可以看出最后兩種方式耗時和最大耗時服務的用時差不多