对于简单的并行任务,可以通过“线程池+Future”的方案来 解决;如果任务之间有聚合关系,无论是AND聚合还是OR聚合,都可以通过CompletableFuture来解决;而批量的并行任务,则可以通过CompletionService来解决
线程池+Future (带返回值,即主线程可以获取子线程的结果,无需获取结果可以去掉Future)
// 线程池
ExecutorService myExecutor = new ThreadPoolExecutor(4,5,1000L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(100));
Future<Integer> f1 = myExecutor.submit(()->{
Thread.sleep(2000);
System.out.println("a");
return 1;
});
Future<Integer> f2 = myExecutor.submit(()->{
Thread.sleep(3000);
System.out.println("b");
return 2;
});
Future<Integer> f3 = myExecutor.submit(()->{
Thread.sleep(1000);
System.out.println("c");
return 3;
});
//主线程阻塞等待线程的结果
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
线程池+FutureTask
FutureTask<Integer> ft1 = new FutureTask<>(() -> {
Thread.sleep(3000);
System.out.println("1111");
return 1;
});
FutureTask<Integer> ft2 = new FutureTask<>(() -> {
Thread.sleep(2000);
System.out.println("2222");
return 2;
});
FutureTask<Integer> ft3 = new FutureTask<>(() -> {
Thread.sleep(1000);
System.out.println("3333");
return 3;
});
myExecutor.submit(ft1);
myExecutor.submit(ft2);
myExecutor.submit(ft3);
Integer result = ft1.get();
System.out.println(result);
Integer result2 = ft2.get();
System.out.println(result2);
Integer result3 = ft3.get();
System.out.println(result3);
线程池+ CompletableFuture
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CompletableFutureTest {
public static void main(String[] args) {
// 起10个线程的线程池
ExecutorService myExecutor = Executors.newFixedThreadPool(10);
Long startTIME = System.currentTimeMillis();
/* 任务一 */
//无返回值得方法 runAsync
CompletableFuture<Void> cf1 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
Long endTIME = System.currentTimeMillis();
Long elapsedTime = endTIME - startTIME;
System.out.println("任务一 elapsedTime="+elapsedTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, myExecutor);
/* 任务二 :与任务一为并行关系*/
//有返回值的方法 supplyAsync
CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {
Integer result2 = 2;
try {
Thread.sleep(4000);
Long endTIME = System.currentTimeMillis();
Long elapsedTime = endTIME - startTIME;
System.out.println("任务二 elapsedTime="+elapsedTime + "; result="+ result2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result2;
}, myExecutor);
/* 任务三 :与任务一为并行关系*/
//有返回值的方法 supplyAsync
CompletableFuture<Integer> cf3 = CompletableFuture.supplyAsync(() -> {
Integer result3 = 1;
try {
Thread.sleep(2000);
Long endTIME = System.currentTimeMillis();
Long elapsedTime = endTIME - startTIME;
System.out.println("任务三 elapsedTime="+elapsedTime + "; result="+ result3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result3;
}, myExecutor);
/** 汇聚任务 **/
/* 任务四 (AND汇聚): 任务一 和 任务二都完成后才开始 */
CompletableFuture<Integer> cf4 = cf2.thenCombine(cf1, (result2,__)->{
Integer result4 = result2;
Long endTIME = System.currentTimeMillis();
Long elapsedTime = endTIME - startTIME;
System.out.println("任务四 elapsedTime="+elapsedTime);
return result4;
});
/* 任务五 (AND汇聚): 任务二 和 任务三都完成后才开始 */
CompletableFuture<Integer> cf5 = cf2.thenCombine(cf3, (result2,result3)->{
Integer result5 = result2+result3;
Long endTIME = System.currentTimeMillis();
Long elapsedTime = endTIME - startTIME;
System.out.println("任务五 elapsedTime="+elapsedTime );
return result5;
});
/* 任务六 (OR汇聚): 任务二 或 任务三 其中一个完成了就开始执行 */
CompletableFuture<Integer> cf6 = cf2.applyToEither(cf3, result -> {
Integer result6 = result;
Long endTIME = System.currentTimeMillis();
Long elapsedTime = endTIME - startTIME;
System.out.println("任务六 elapsedTime="+elapsedTime);
return result6;
});
System.out.println("任务四 result :"+cf4.join());
System.out.println("任务五 result :"+cf5.join());
System.out.println("任务六 result :"+cf6.join());
}
}
任务一 elapsedTime=1053
任务三 elapsedTime=2054; result=1
任务六 elapsedTime=2054
任务二 elapsedTime=4053; result=2
任务五 elapsedTime=4053
任务四 elapsedTime=4053
任务四 result :2
任务五 result :3
任务六 result :1
线程池+CompletionService
以下使用场景可以使用 CompletionService 来实现:
1、多个任务并发执行,先完成的任务执行下一步骤。
2、相同任务分给多个线程并发执行,其中一个返回结果就结束剩余的所有任务
import java.util.concurrent.*;
public class CompletionServiceTest {
public static void main(String[] args) {
ExecutorService myExecutor = Executors.newFixedThreadPool(10);
Long startTIME = System.currentTimeMillis();
// 创建CompletionService
CompletionService<Integer> completionService = new ExecutorCompletionService<>(myExecutor);
completionService.submit(()->{
Thread.sleep(3000);
Long endTIME = System.currentTimeMillis();
Long elapsedTime = endTIME - startTIME;
System.out.println("任务一 elapsedTime=" + elapsedTime);
return 1;
});
completionService.submit(()->{
Thread.sleep(1000);
Long endTIME = System.currentTimeMillis();
Long elapsedTime = endTIME - startTIME;
System.out.println("任务二 elapsedTime=" + elapsedTime);
return 2;
});
completionService.submit(()->{
Thread.sleep(2000);
Long endTIME = System.currentTimeMillis();
Long elapsedTime = endTIME - startTIME;
System.out.println("任务三 elapsedTime=" + elapsedTime);
return 3;
});
for(int i =0 ; i<3;i++) {
try{
Future<Integer> future= completionService.take();
Integer r = future.get();
System.out.println("任务结果=" + r);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("任务结束" );
}
}
任务二 elapsedTime=1050
任务结果=2
任务三 elapsedTime=2050
任务结果=3
任务一 elapsedTime=3050
任务结果=1
任务结束