CompletionService用来异步获取ExecutorService的执行结果,因为用了阻塞队列,所以先出的结果先获取。目前只有一个实现类ExecutorCompletionService。
下面是示例Demo:场景是,三个耗时操作分别进行,最后将处理结果给主线程的另一个子线程保存结果。
结构为
CompletionServiceDemo.java
package com.example.demo.concurrent.completionservice;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.*;
@Slf4j
public class CompletionServiceDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
BlockingQueue blockingQueue = new LinkedBlockingQueue(10);
CompletionService completionService = new ExecutorCompletionService(executorService,blockingQueue);
completionService.submit(new MyCallableA());
completionService.submit(new MyCallableB());
completionService.submit(new MyCallableC());
try {
for (int i = 0; i < 3 ; i++) {
Result result = (Result) completionService.take().get();
executorService.execute(new MyThread(result));
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
MyCallableA.java,MyCallableB.java,MyCallableC.java三个类代码一样,名称不同。
package com.example.demo.concurrent.completionservice;
import lombok.extern.slf4j.Slf4j;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@Slf4j
public class MyThread extends Thread {
private Result result;
public MyThread(Result rs) {
result = rs;
}
@Override
public void run() {
log.info("执行线程保存处理结果-----开始----");
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
log.info("执行线程保存处理结果-----保存结果:{}----",result.toString());
log.info("执行线程保存处理结果-----结束----");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
MyThread.java用于执行处理的结果。
package com.example.demo.concurrent.completionservice;
import lombok.extern.slf4j.Slf4j;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
@Slf4j
public class MyCallableA implements Callable<Result> {
@Override
public Result call() throws Exception {
log.info("执行MyCallableA-----");
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
Result result = new Result("MyCallableA","19");
return result;
}
}
另一个是结果对象Result.java
package com.example.demo.concurrent.completionservice;
import lombok.Data;
@Data
public class Result {
private String name;
private String age;
public Result(String name, String age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Result{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
执行结果如下:
Connected to the target VM, address: '127.0.0.1:62249', transport: 'socket'
00:16:41.462 [pool-1-thread-3] INFO com.example.demo.concurrent.completionservice.MyCallableC - 执行MyCallableC-----
00:16:41.462 [pool-1-thread-1] INFO com.example.demo.concurrent.completionservice.MyCallableA - 执行MyCallableA-----
00:16:41.462 [pool-1-thread-2] INFO com.example.demo.concurrent.completionservice.MyCallableB - 执行MyCallableB-----
00:16:46.483 [pool-1-thread-1] INFO com.example.demo.concurrent.completionservice.MyThread - 执行线程保存处理结果-----开始----
00:16:47.482 [pool-1-thread-3] INFO com.example.demo.concurrent.completionservice.MyThread - 执行线程保存处理结果-----开始----
00:16:48.482 [pool-1-thread-2] INFO com.example.demo.concurrent.completionservice.MyThread - 执行线程保存处理结果-----开始----
00:16:48.482 [pool-1-thread-2] INFO com.example.demo.concurrent.completionservice.MyThread - 执行线程保存处理结果-----保存结果:Result{name='MyCallableB', age='19'}----
00:16:48.484 [pool-1-thread-2] INFO com.example.demo.concurrent.completionservice.MyThread - 执行线程保存处理结果-----结束----
00:16:49.485 [pool-1-thread-1] INFO com.example.demo.concurrent.completionservice.MyThread - 执行线程保存处理结果-----保存结果:Result{name='MyCallableA', age='19'}----
00:16:49.485 [pool-1-thread-1] INFO com.example.demo.concurrent.completionservice.MyThread - 执行线程保存处理结果-----结束----
00:16:51.483 [pool-1-thread-3] INFO com.example.demo.concurrent.completionservice.MyThread - 执行线程保存处理结果-----保存结果:Result{name='MyCallableC', age='19'}----
00:16:51.483 [pool-1-thread-3] INFO com.example.demo.concurrent.completionservice.MyThread - 执行线程保存处理结果-----结束----
这里有几个对象很重要。
//真正执行线程的Service
ExecutorService executorService = Executors.newFixedThreadPool(3);
//阻塞队列,用来保存异步线程处理结果
BlockingQueue blockingQueue = new LinkedBlockingQueue(10);
//把真正处理异步线程的对象与阻塞队列关联起来
CompletionService completionService = new ExecutorCompletionService(executorService,blockingQueue);
最后通过
completionService.take().get();
获取到结果,分别处理。
注意:
1.先处理完的将先放到队列中
2.如果不新建阻塞队列,默认会创建一个new LinkedBlockingQueue<Future<V>>(),大小为Integer.MAX_VALUE。
3.submit方式有两种
submit(Callable<V> task)或者
submit(Runnable task, V result)