当前位置: 首页 > 面试题库 >

如何使用invokeAll()让所有线程池执行任务?

诸葛茂勋
2023-03-14
问题内容
    ExecutorService pool=Executors.newFixedThreadPool(7);
        List<Future<Hotel>> future=new ArrayList<Future<Hotel>>();
        List<Callable<Hotel>> callList = new ArrayList<Callable<Hotel>>();

        for(int i=0;i<=diff;i++){

            String str="2013-"+(liDates.get(i).get(Calendar.MONTH)+1)+"-"+liDates.get(i).get(Calendar.DATE);

            callList.add(new HotelCheapestFare(str));

        }       
     future=pool.invokeAll(callList);
for(int i=0;i<=future.size();i++){

        System.out.println("name is:"+future.get(i).get().getName());
    }

现在我想invokeAll在进入for循环之前集中所有任务,但是当我运行此程序时,for循环会在invokeAll此之前执行并引发此异常:

java.util.concurrent.ExecutionException: java.lang.NullPointerException at 
java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source) at  
java.util.concurrent.FutureTask.get(Unknown Source) at 
com.mmt.freedom.cheapestfare.TestHotel.main(TestHotel.java:6‌​5)

Caused by: java.lang.NullPointerException at 
com.mmt.freedom.cheapestfare.HotelCheapestFare.getHotelCheap‌estFare(HotelCheapes‌​tFare.java:166) 
at com.mmt.freedom.cheapestfare.HotelCheapestFare.call(HotelChe‌​apestFare.java:219)
at com.mmt.freedom.cheapestfare.HotelCheapestFare.call(HotelChe‌​apestFare.java:1) 
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source) at java.util.concurrent.FutureTask.run(Unknown Source) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) atjava.util.concurrent.ThreadPoolExecutor$Worker.run(Unknow‌​n Source)
at java.lang.Thread.run

问题答案:

一种ExecutorService工作方式是,当您调用invokeAll它时,它等待所有任务完成:

执行给定的任务,并在所有任务完成时返回保存其状态和结果的期货列表。Future.isDone()对于返回列表的每个元素为true。
请注意,已完成的任务可能已正常终止或引发了异常而终止
。如果在进行此操作时修改了给定的集合,则此方法的结果不确定。1(强调)

这意味着您的任务已全部完成,但有些可能会引发异常。此异常是Future-调用的一部分,get导致将异常重新包装在ExecutionException

从你的stacktrack

java.util.concurrent.ExecutionException: java.lang.NullPointerException at
java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source) at
java.util.concurrent.FutureTask.get(Unknown Source) at 
                                ^^^ <-- from get

您可以看到确实如此。使用NPE,您的任务之一失败了。在ExecutorService捕捉到的异常,并抛出一个告诉你这件事ExecutionException,当你调用Future.get

现在,如果您要在完成任务时执行任务 ,则
需要一个ExecutorCompletionService。这样BlockingQueue可以使您在完成任务时轮询任务。

public static void main(String[] args) throws Exception {
    final ExecutorService executorService = Executors.newFixedThreadPool(10);
    final ExecutorCompletionService<String> completionService = new ExecutorCompletionService<>(executorService);
    executorService.submit(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < 100; ++i) {
                try {
                    final Future<String> myValue = completionService.take();
                    //do stuff with the Future
                    final String result = myValue.get();
                    System.out.println(result);
                } catch (InterruptedException ex) {
                    return;
                } catch (ExecutionException ex) {
                    System.err.println("TASK FAILED");
                }
            }
        }
    });
    for (int i = 0; i < 100; ++i) {
        completionService.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                if (Math.random() > 0.5) {
                    throw new RuntimeException("FAILED");
                }
                return "SUCCESS";
            }
        });
    }
    executorService.shutdown();
}

在这个例子中,我有一个任务调用takeExecutorCompletionService它得到了FutureS作为他们变得可用,然后我提交任务了ExecutorCompletionService

这样一来,您就可以在失败后立即获得失败的任务,而不必等待所有任务一起失败。

唯一的麻烦是,由于现在所有事物都是异步的,因此很难告诉轮询线程所有任务都已完成。在这种情况下,我已经知道将要提交100个任务,因此只需要轮询100次即可。更通用Futuresubmit方法是也从方法中收集s
,然后循环遍历以查看是否已完成。



 类似资料:
  • 如果每个任务(线程)有多个阶段。那么如何确保所有任务执行第1阶段,然后执行第2阶段,依此类推。例如如何修改下面的代码,使我的输出为:Task1的第1阶段、Task2的第1阶段、Task3的第1阶段、Task1的第2阶段、Task2的第2阶段、Task3的第2阶段,依此类推...

  • 本文向大家介绍Java 使用线程池执行多个任务的示例,包括了Java 使用线程池执行多个任务的示例的使用技巧和注意事项,需要的朋友参考一下 在执行一系列带有IO操作(例如下载文件),且互不相关的异步任务时,采用多线程可以很极大的提高运行效率。线程池包含了一系列的线程,并且可以管理这些线程。例如:创建线程,销毁线程等。本文将介绍如何使用Java中的线程池执行任务。 1 任务类型 在使用线程池执行任务

  • 在我的项目中,我正在构建一个Java的执行框架,它接收来自客户端的工作请求。工作(大小不同)被分解为一组任务,然后排队等待处理。有单独的队列来处理每种类型的任务,每个队列都与一个ThreadPool相关联。ThreadPools的配置方式使引擎的整体性能达到最佳。 这种设计有助于我们有效地平衡请求的负载,大型请求不会占用系统资源。然而,当一些队列为空并且它们各自的线程池闲置时,该解决方案有时会变得

  • 我正在使用线程池执行器更改遗留设计。详情如下:- 遗留:-对于遗留设计,在应用程序启动时创建600个线程。和放置在各种池中,然后在需要时提取这些池,并将任务分配给相应的线程。 新:-在新设计中,我将线程池替换为执行器服务 我观察到的是,对于Executor,在启动时不会创建线程。它们是在从客户端激发请求时创建的。因此,与前一个线程相比,在内存中创建的线程要少得多。 但我的问题是,这样做是否正确,因

  • 我正在使用Spring,我有一个计划任务,可以对数据库进行一些操作。我发现这个任务是在每个池上执行的,而我只希望执行一次。例如,在我的日志文件中,我读到: 我有这样的配置: 这就是任务: 可能吗?谢谢

  • 我有一个类,它基本上会做两次相同的步骤。听起来像是一个在哪里多线程处理程序的完美例子。我的问题是,如果我只需要两个线程就可以做到这一点。以下是一般情况 我已经完成了第一部分——构建对象——的工作。我现在的问题是- 如何让主线程等待两个线程完成其第一部分?也许main会在两个对象上执行等待,然后在线程notifyAll之后,它们会在主线程上执行等待?但是线程如何抓住主线程呢?也许用这个 我怎样才能在