我正在寻找一个协调多个多线程任务的好解决方案。
基本上我有2个任务,我调用A
和B
需要在与主线程不同的线程上执行。
但必须在B
完成后启动A
。 A
和B
他们自己包含几个应该并行运行的部分,称为A1, A2, ... B1, B2, ...
。
并且有一个来自外部的来电者,无论进展如何,都需要重新启动整个工作。我怎么能这样做呢?如果每个子任务(A1,...)已经完成,我想创建一些保存信息的布尔数组,如果是,则启动B.如果已经取消,则检查每个方法中的每几行代码。 但在我看来,这不是一个优雅的解决方案,并且有可能以令人兴奋的方式协调这一点。
答案 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解决方案