任务编排实现

时间:2016-07-31 20:06:19

标签: java multithreading

我无法为需要协调不同任务的程序实现优雅的功能样式解决方案。这就是我想要实现的目标。

我有三个类我想要编排的方法(简化为简洁):

class TaskA {
    public ResultA call() {
        return new ResultA();
    }
}

class TaskB {
    public ResultB call(ResultA a) {
        return new ResultB();
    }
}

class TaskC {
    public ResultC call(List<ResultB> resultBs) {
        return new ResultC();
    }
}

我需要执行TaskA&#39; n&#39;并行时间和TaskA的每次执行,我需要执行TaskB&#39; n&#39;使用相应TaskA的结果的时间。最后,我需要使用TaskC的所有调用的结果执行TaskB

实现这一目标的一种方法是创建一个Callable来封装对TaskATaskB的调用,最后在我的主线程中,收集List的{要Future执行ResultB的{​​1}} {/ p>}

TaskC

在我的主线上:

class TaskATaskBCallable implements Callable<ResultB> {
    private TaskA taskA ...;
    private TaskB taskB ...;

    public ResultB call() {
        return taskB.call(taskA.call());
    }
}

我不喜欢这个解决方案的一件事是private ResultC orchestrate() { ExecutorService service = ...; List<Callable<ResultB>> callables = ...; taskC.call(callables.map(callable -> service.submit(callable)).map(Future::get).collect(Collectors.toList()); } 。这可能是一个不必要的类耦合TaskATaskBCallableTaskA。此外,如果我必须将另一个任务链接到TaskBTaskA,我将不得不修改TaskB也可能修改其名称。我觉得我可以通过更智能地使用像TaskATaskBCallableCompletableFuture这样的Java并发库类来摆脱它。

任何指针?

2 个答案:

答案 0 :(得分:0)

我找到了一种使用CompletableFuture执行此操作的方法:

private ResultC orchestrate() {
    ExecutorService service = ...;
    int taskCount = ...;

    List<CompletableFuture<ResultB>> resultBFutures = IntStream.rangeClosed(1, taskCount)
                    .mapToObj((i) -> CompletableFuture.supplyAsync(() -> new TaskA().call(), service))
                    .map(resultAFuture -> resultAFuture.thenApplyAsync(resultA -> new TaskB().call(resultA),
                                    service))
                    .collect(Collectors.toList());

    return new TaskC().call(CompletableFuture.allOf(resultBFutures.toArray(new CompletableFuture[resultBFutures.size()]))
                    .thenApply(v -> resultBFutures.stream().map(CompletableFuture::join)
                                    .collect(Collectors.toList()))
                    .join());
}

答案 1 :(得分:-1)

我认为CompletableFuture确实会证明最优雅:

    int taskCount = 100;

    List<ResultB> resultBs = IntStream.range(0, taskCount)
            .mapToObj(i -> new TaskA())
            .map(taskA -> CompletableFuture.supplyAsync(taskA::call))
            .map(completableFutureA -> completableFutureA.thenApplyAsync(new TaskB()::call))
            .collect(Collectors.toList()) // collect, in order to kick off the async tasks
            .stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toList());
    return new TaskC().call(resultBs);