Java并发:协调多个任务并取消

时间:2015-03-10 10:34:48

标签: java multithreading concurrency

我正在寻找一个协调多个多线程任务的好解决方案。

基本上我有2个任务,我调用AB需要在与主线程不同的线程上执行。

但必须在B完成后启动AAB他们自己包含几个应该并行运行的部分,称为A1, A2, ... B1, B2, ...

并且有一个来自外部的来电者,无论进展如何,都需要重新启动整个工作。我怎么能这样做呢?如果每个子任务(A1,...)已经完成,我想创建一些保存信息的布尔数组,如果是,则启动B.如果已经取消,则检查每个方法中的每几行代码。 但在我看来,这不是一个优雅的解决方案,并且有可能以令人兴奋的方式协调这一点。

enter image description here

3 个答案:

答案 0 :(得分:2)

在Java8中,您可以使用CompletableFutures。方法execA引发三个并行任务并返回一个包含所有这些任务的CompletableFuture。 execB等待此复合任务完成,然后设置自己的一组任务。最后,main方法中的get等待B方法完成。

public class Futures {
    String name;
    int value;

    public static void main(String[] args) {
        try {
        execB(execA()).get();
        } catch(InterruptedException|ExecutionException e) {}
    }
    Futures(String name, int value) {
        this.name = name;
        this.value = value;
    }

    void runMethod() {
        System.out.println("Entering " + name);
        try {
            Thread.sleep(value * 1000);
        } catch(InterruptedException e) {}
        System.out.println("Exiting " + name);
    }
    public static CompletableFuture<Void> execA() {
        return(
            CompletableFuture.<Void>allOf(
            CompletableFuture.runAsync(() -> (new Futures("a1", 4)).runMethod()),
            CompletableFuture.runAsync(() -> (new Futures("a2", 2)).runMethod()),
            CompletableFuture.runAsync(() -> (new Futures("a3", 1)).runMethod()))
        );
    }
    public static CompletableFuture<Void> execB(CompletableFuture<Void> prev) {
        try {
            prev.get();
        } catch (InterruptedException|ExecutionException e) {}
        return(
            CompletableFuture.<Void>allOf(
            CompletableFuture.runAsync(() -> (new Futures("b1", 2)).runMethod()),
            CompletableFuture.runAsync(() -> (new Futures("b2", 3)).runMethod()),
            CompletableFuture.runAsync(() -> (new Futures("b3", 1)).runMethod())));
    }
}

答案 1 :(得分:0)

以下是使用countDownLatches和Exectors的示例实现:

public class Test {
    static ExecutorService maintaskExecutor = Executors.newFixedThreadPool(2);

    private static CountDownLatch latch = new CountDownLatch(0);


    public Test() {
    }


    public static void main(String[] args) {
        maintaskExecutor.submit(new runnableA());
        maintaskExecutor.submit(new runnableB());

    }

    private void restart() {
        maintaskExecutor.shutdownNow();
        maintaskExecutor.submit(new runnableA());
        maintaskExecutor.submit(new runnableB());
    }


    private static class runnableA implements Runnable {
        ExecutorService taskExecutorA = Executors.newFixedThreadPool(3);
        private final CountDownLatch latchA = new CountDownLatch(3);


        @Override
        public void run() {

            try {
                Runnable a1Runnable = createA1Runnable();
                Runnable a2Runnable = createA1Runnable();
                Runnable a3Runnable = createA1Runnable();

                taskExecutorA.submit(a1Runnable);
                taskExecutorA.submit(a2Runnable);
                taskExecutorA.submit(a3Runnable);

                latchA.await();
                latch.countDown();
            } catch (InterruptedException e) {
                taskExecutorA.shutdownNow();
            }
        }

        private Runnable createA1Runnable() {
            return new Runnable() {
                @Override
                public void run() {
                    //Design this task to respond to interruption by checking if the thread has been interrupted
                    while(!Thread.interrupted()){
                        //Do the work
                    }

                    return;
                }
            };
        }
    }

      private  static class runnableB implements Runnable{
              private final CountDownLatch latch = new CountDownLatch(3);
              ExecutorService taskExecutorB = Executors.newFixedThreadPool(3);

              public void run(){
                  try {
                    latch.await();
                    //Creates the tasks B1, B2, ...


                } catch (InterruptedException e) {
                    taskExecutorB.shutdownNow();
                }
             }
}

}

答案 2 :(得分:0)

假设您需要子任务的输出,您可以在CompletableFuture中使用thenCombine

    CompletableFuture<String> a1 = CompletableFuture.supplyAsync(() -> "a1");
    CompletableFuture<String> a2 = CompletableFuture.supplyAsync(() -> "a2");
    CompletableFuture<String> a3 = CompletableFuture.supplyAsync(() -> "a3");
    CompletableFuture<String> a = a1.thenCombine(a2, (a1r, a2r) -> "combination of a1 and a2").thenCombine(a3,
            (a1anda2r, a3r) -> "combination of a1,a2,a3");

    CompletableFuture<String> b1 = CompletableFuture.supplyAsync(() -> "a1");
    CompletableFuture<String> b2 = CompletableFuture.supplyAsync(() -> "a2");
    CompletableFuture<String> b3 = CompletableFuture.supplyAsync(() -> "a3");
    CompletableFuture<String> b = a.thenCombine(b1, (ar, b1r) -> "combination of a and b1")
            .thenCombine(b2, (aAndb1, b2r) -> "combination of a,b1,b2")
            .thenCombine(b3, (aAndb1Andb2, b3r) -> "combination of A and B");

如果不需要输出,您可以使用Neil Masson的allOf解决方案