欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > java >内容正文

java

java面试-Java并发编程(九)——批量获取多条线程的执行结果

发布时间:2025/3/20 java 51 豆豆
生活随笔 收集整理的这篇文章主要介绍了 java面试-Java并发编程(九)——批量获取多条线程的执行结果 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

当向线程池提交callable任务后,我们可能需要一次性获取所有返回结果,有三种处理方法。

方法一:自己维护返回结果

// 创建一个线程池 ExecutorService executorService = Executors.newFixedThreadPool(10);// 存储执行结果的List List<Future<String>> results = new ArrayList<Future<String>>();// 提交10个任务 for ( int i=0; i<10; i++ ) {Future<String> result = executorService.submit( new Callable<String>(){public String call(){int sleepTime = new Random().nextInt(1000);Thread.sleep(sleepTime);return "线程"+i+"睡了"+sleepTime+"秒";}} );// 将执行结果存入results中results.add( result ); }// 获取10个任务的返回结果 for ( int i=0; i<10; i++ ) {// 获取包含返回结果的future对象Future<String> future = results.get(i);// 从future中取出执行结果(若尚未返回结果,则get方法被阻塞,直到结果被返回为止)String result = future.get();System.out.println(result); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

此方法的弊端:

  • 需要自己创建容器维护所有的返回结果,比较麻烦;
  • 从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住,如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。
  • 方法二:使用ExecutorService的invokeAll函数

    本方法能解决第一个弊端,即并不需要自己去维护一个存储返回结果的容器。当我们需要获取线程池所有的返回结果时,只需调用invokeAll函数即可。 
    但是,这种方式需要你自己去维护一个用于存储任务的容器。

    // 创建一个线程池 ExecutorService executorService = Executors.newFixedThreadPool(10);// 创建存储任务的容器 List<Callable<String>> tasks = new ArrayList<Callable<String>>();// 提交10个任务 for ( int i=0; i<10; i++ ) {Callable<String> task = new Callable<String>(){public String call(){int sleepTime = new Random().nextInt(1000);Thread.sleep(sleepTime);return "线程"+i+"睡了"+sleepTime+"秒";}};executorService.submit( task );// 将task添加进任务队列tasks.add( task ); }// 获取10个任务的返回结果 List<Future<String>> results = executorService.invokeAll( tasks );// 输出结果 for ( int i=0; i<10; i++ ) {// 获取包含返回结果的future对象Future<String> future = results.get(i);// 从future中取出执行结果(若尚未返回结果,则get方法被阻塞,直到结果被返回为止)String result = future.get();System.out.println(result); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    方法三:使用CompletionService

    CompletionService内部维护了一个阻塞队列,只有执行完成的任务结果才会被放入该队列,这样就确保执行时间较短的任务率先被存入阻塞队列中。

    ExecutorService exec = Executors.newFixedThreadPool(10);final BlockingQueue<Future<Integer>> queue = new LinkedBlockingDeque<Future<Integer>>( 10); //实例化CompletionService final CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>( exec, queue); // 提交10个任务 for ( int i=0; i<10; i++ ) {executorService.submit( new Callable<String>(){public String call(){int sleepTime = new Random().nextInt(1000);Thread.sleep(sleepTime);return "线程"+i+"睡了"+sleepTime+"秒";}} ); }// 输出结果 for ( int i=0; i<10; i++ ) {// 获取包含返回结果的future对象(若整个阻塞队列中还没有一条线程返回结果,那么调用take将会被阻塞,当然你可以调用poll,不会被阻塞,若没有结果会返回null,poll和take返回正确的结果后会将该结果从队列中删除)Future<String> future = completionService.take();// 从future中取出执行结果,这里存储的future已经拥有执行结果,get不会被阻塞String result = future.get();System.out.println(result); }

    总结

    以上是生活随笔为你收集整理的java面试-Java并发编程(九)——批量获取多条线程的执行结果的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。