Met simultaneously to multiple service requests scenes at work, where his research about the process of recording
Analog three requests requestA, requestB, requestC:
@Service public class ParallelService { public String requestA() { try { TimeUnit.MILLISECONDS.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return "A"; } public String requestB() { try { TimeUnit.MILLISECONDS.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return "B"; } public String requestC() { try { TimeUnit.MILLISECONDS.sleep(2500); } catch (InterruptedException e) { e.printStackTrace(); } return "C"; } }
Establishing a test class ParallelController, request method is used to simulate different service requests:
@Slf4j
@RestController @RequestMapping("parallel") public class ParallelController { @Autowired private ParallelService parallelService; private String request(int index) { if (index == 0) { return parallelService.requestA(); } if (index == 1) { return parallelService.requestB(); } if (index == 2) { return parallelService.requestC(); } return null; } }
Then, they begin to experiment with different ways of request:
Serial (the traditional way)
/ * * * Serial (traditional request) * / @GetMapping ( " / test1 " ) public void test1 () { Long Start = System.currentTimeMillis (); List <String> List = new new the ArrayList <> (); IntStream. Range ( 0 , . 3 ) .forEach (index -> { List.add (Request (index)); }); log.info ( " serial response result: {}, long response: {} " , of Arrays.toString (List.toArray ()), System.currentTimeMillis () - Start); }
Using JMeter for pressure measurement, pressure measurement parameters are as follows:
Create 30 threads, cycle requests within 20 seconds, the results:
The results can be seen from the console: The request is sequentially performed, the result is [A, B, C], very stable long response
JMeter can be seen from the results: The average duration of response: 5805ms , the minimum length of the response: 5507ms, when the maximum length of the response: 6497ms, QPS: 5.0 / sec
parallel
Parallel flow java8 syntax used, the use of multi-core processors to simultaneously request, when the request acquiring all the results after termination
/** * 并行请求 */ @GetMapping("/test2") public void test2() { long start = System.currentTimeMillis(); List<String> list = new ArrayList<>(); IntStream.range(0, 3).parallel().forEach(index -> { list.add(request(index)); }); log.info("java8并行,响应结果:{},响应时长:{}", Arrays.toString(list.toArray()), System.currentTimeMillis() - start); }
使用jmeter同样的参数压测,结果:
从控制台结果可以看到:请求是独立执行没有顺序,所以结果是不确定的,响应时长很不稳定
从JMeter结果可以看到:平均响应时长:16648ms,最小响应时长:2513ms,最大响应时长:36052ms,QPS:1.3/sec
多线程
多线程的处理方式是,创建多个线程,分别去请求,当获取所有请求结果后才终止
/** * 多线程请求 */ @GetMapping("/test3") public void test3() { long start = System.currentTimeMillis(); List<String> list = new ArrayList<>(); List<Future<String>> futureList = new ArrayList<>(); ExecutorService executor = Executors.newFixedThreadPool(3); // 开启3个线程 IntStream.range(0, 3).forEach(index -> { Future<String> task = executor.submit(() -> request(index)); futureList.add(task); }); for (Future<String> future : futureList) { try { // 如果任务执行完成,future.get()方法会返回Callable任务的执行结果。 // future.get()方法会产生阻塞,所有线程都阻塞在这里,当获取到一个结果后,才执行下一个 list.add(future.get()); } catch (Exception e) { log.error(e.getMessage(), e); } } // 停止接收新任务,原来的任务继续执行 executor.shutdown(); log.info("多线程,响应结果:{},响应时长:{}", Arrays.toString(list.toArray()), System.currentTimeMillis() - start); }
从控制台结果可以看到:请求是顺序执行的,结果都是[A, B, C],响应时长比较稳定
从JMeter结果可以看到:平均响应时长:2505ms,最小响应时长:2503ms,最大响应时长:2519,QPS:11.4/sec
结论:
1、串行处理多请求,代码很简单,响应时长是每个请求时长的总和,很稳定但是效率不高
2、使用java8并行处理,代码很简单,响应时长很不稳定,效率也不高,不建议使用
3、使用多线程处理时,代码复杂,响应时长为单个请求中时长最长的那个,效率很高,推荐使用