【问题标题】:Java ExecutorService invokeAll with different types [duplicate]具有不同类型的Java ExecutorService invokeAll [重复]
【发布时间】:2021-12-01 01:07:15
【问题描述】:

我使用的是 Java 1.7。

我正在尝试同时执行两种方法。但是,每种方法都有不同的返回类型。

我有以下:

private ExecutorService executorService = Executors.newFixedThreadPool(2);

private void executeConcurrentTasks(final boolean autoBookingEnabled, final TripDTO tripDTO, final ApprovalRequestDetails approvalRequestDetails, final ApprovalRequest approvalRequest, final QuoteResponse quoteResponse, final TripRequirementsResponse tripRequirementsResponse, final List<List<Evaluator>> evaluatorsList, final List<EvaluationApprovalTree> evaluationTree, final Long memberId, final Map<String,Object> properties, final HttpSession session) {

    List<Callable<?>> tasks = Arrays.asList(
        new Callable<BookServicesResponse>() {
            public BookServicesResponse call() throws Exception {
                BookServicesResponse autoBookResponse = bookServices(autoBookingEnabled, tripDTO, approvalRequestDetails, approvalRequest, quoteResponse, memberId, properties, session);
                return autoBookResponse;
            }
        },
        new Callable<ApprovalResponse>() {
            public ApprovalResponse call() throws Exception {
                ApprovalResponse approvalResponse = submitApproval(approvalRequest, tripDTO, tripRequirementsResponse, evaluatorsList, evaluationTree, memberId, properties, session);
                return approvalResponse;
            }
        });

    List<Future<?>> futures = executorService.invokeAll(tasks); // compile error
    
    for (Future<?> future : futures) {
        try {
            Object obj = future.get();
            if (obj instanceof BookServicesResponse) {
                // ...
            } else if (obj instanceof ApprovalResponse) {
                // ...
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

编译错误:

问题

是否有一种通用的方式来处理这两个方法的调用,使得返回的期货列表每个都有不同的对象?

【问题讨论】:

  • 如果您要将它们全部放入一个列表中,那么也许您应该使用List&lt;Callable&lt;Object&gt;&gt;(当然也可以使用new Callable&lt;Object&gt;(){...} 实例化您的可调用对象。无论如何,这不会是最糟糕的部分, 因为你已经必须转换了。就打字而言,我认为 invokeAll 最适合统一类型的可调用对象。

标签: java concurrency threadpool executorservice


【解决方案1】:

因为invokeAll 需要List&lt;? extends Callable&lt;T&gt;&gt; 而不是List&lt;? extends Callable&lt;? extends T&gt;&gt; 类型的参数,所以它不起作用。您可以认为这是 API 的一个缺点。

为了解决这个问题,您可以使用List&lt;Callable&lt;Object&gt;&gt; 或使用BookServicdsResponseArrovalResponse 的公共超类(在此示例中我将使用Response):

List<Callable<Response>> tasks = Arrays.asList(
        new Callable<Response>() {
            public Response call() throws Exception {
                BookServicesResponse autoBookResponse = bookServices(autoBookingEnabled, tripDTO, approvalRequestDetails, approvalRequest, quoteResponse, memberId, properties, session);
                return autoBookResponse;
            }
        },
        new Callable<Response>() {
            public Response call() throws Exception {
                ApprovalResponse approvalResponse = submitApproval(approvalRequest, tripDTO, tripRequirementsResponse, evaluatorsList, evaluationTree, memberId, properties, session);
                return approvalResponse;
            }
        });

    List<Future<Response>> futures = executorService.invokeAll(tasks); // compile error

您也可以像这样使用“不安全”演员表:

List<Future<?>> futures = executorService.invokeAll((List<Callable<Object>>) tasks);

由于您只会从Callables 中检索元素,因此这不会导致不需要的ClassCastExceptions。

【讨论】:

    【解决方案2】:

    我不知道这是否是最好的解决方案,它实际上并没有回答如何使用泛型来获得不同可调用对象列表的问题。但我最终使用了两个单独的 Callables 和 Futures。

        Callable<BookServicesResponse> taskBook = new Callable<BookServicesResponse>() {
                public BookServicesResponse call() throws Exception {
                    BookServicesResponse autoBookResponse = bookServices(autoBookingEnabled, tripDTO, approvalRequestDetails, approvalRequest, quoteResponse, memberId, properties, session);
                    return autoBookResponse;
                }
            };
    
        Callable<ApprovalResponse> taskApprove = new Callable<ApprovalResponse>() {
                public ApprovalResponse call() throws Exception {
                    ApprovalResponse approvalResponse = submitApproval(approvalRequest, tripDTO, tripRequirementsResponse, evaluatorsList, evaluationTree, memberId, properties, session);
                    return approvalResponse;
                }
            };
    
        Future<BookServicesResponse> futureBook = executorService.submit(taskBook);
        Future<ApprovalResponse> futureApprove = executorService.submit(taskApprove);
    

    【讨论】:

    • 看起来不错。另一种方法似乎很复杂。您可以创建一个响应接口并使用两个响应类对其进行扩展。但可能没有通用接口。所以你最终会转换响应对象。顺便说一句,如果您将 > 替换为 .,您问题中的代码将起作用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多