最近看了CompletionService使用总结-CSDN博客
学习了一下里面的用法,自己写了个测试类
记录一下,个人感觉,这里主要是把线程池套在ExecutorCompletionService这个壳里,然后用它的take和poll方法
/**
* @Author: XXX
* @CreateTime: 2023 - 10 - 27
* @Description: 接口CompletionService的功能是以异步的方式一边生产新的任务,一边处理已完成任务的结果,
* 这样可以将执行任务与处理任务分离开来进行处理。使用submit执行任务,使用take取得已完成的任务,并按照完成这些任务的时间顺序处理它们的结果。
*/
public class CompletionServiceTest {
/**
* 接口CompletionService的结构比较简洁,仅有一个实现类ExecutorCompletionService,
* 类ExecutorCompletionService需要依赖于Executor对象,大部分的实现也就是实现线程池ThreadPoolExecutor对象。
*
* @param args
*/
public static void main(String[] args) throws Exception {
// 设置线程池,3个核心线程
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(3, 3, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10));
ExecutorCompletionService<Object> executorCompletionService = new ExecutorCompletionService<>(threadPoolExecutor);
// // 使用take()方法,谁先做完把谁取出来
// test1(executorCompletionService);
// // 使用poll()方法,直接开始取,取不到就null
// test2(executorCompletionService);
// // 使用poll(long timeout,TimeUnit unit) 方法,到了规定的时间开始取,取不到返回null
// test3(executorCompletionService);
// 使用get()方法,等到指定的future执行完了再get它的结果
test4(executorCompletionService);
}
/**
* 方法take()取得最先完成任务的Future对象,谁执行时间最短谁最先返回,即方法take()是按任务执行的速度,从快到慢的顺序获得Future对象。
*
* @param executorCompletionService
* @throws InterruptedException
* @throws ExecutionException
*/
private static void test1(ExecutorCompletionService<Object> executorCompletionService) throws Exception {
// 设置5个任务
for (int i = 0; i < 5; i++) {
Integer number = i;
// Future和Callable一般是配合使用起来的。相比Runnable,Callable多了返回值,可以返回结果/异常,由Future对象接收。
executorCompletionService.submit(() -> {
task(number);
}, "任务" + number + "已完成");
}
for (int i = 0; i < 5; i++) {
Thread.sleep(5);
System.out.println(executorCompletionService.take().get());
}
}
/**
* 方法poll()的作用是获取并移除表示下一个已完成任务的Future,如果不存在这样的任务,则返回null,方法poll()无阻塞的效果。
* take和poll的区别:
* take()如果队列中没有数据,则线程会wait并释放CPU,而poll()则会直接返回null。
*
* @param executorCompletionService
* @throws Exception
*/
private static void test2(ExecutorCompletionService<Object> executorCompletionService) throws Exception {
// 设置5个任务
for (int i = 0; i < 5; i++) {
Integer number = i;
// Future和Callable一般是配合使用起来的。相比Runnable,Callable多了返回值,可以返回结果/异常,由Future对象接收。
executorCompletionService.submit(() -> {
task(number);
}, "任务" + number + "已完成");
}
for (int i = 0; i < 5; i++) {
// poll队列的时候还没任务做完,所以返回null,这时候get()就空指针了
System.out.println(executorCompletionService.poll());
}
}
/**
* 方法Future<V> poll(long timeout,TimeUnit unit)的作用是等待指定的timeout时间,在timeout时间之内获取到值时立即向下继续执行,如果超时也立即向下执行。
*
* @param executorCompletionService
* @throws Exception
*/
private static void test3(ExecutorCompletionService<Object> executorCompletionService) throws Exception {
// 设置5个任务
for (int i = 0; i < 5; i++) {
Integer number = i;
// Future和Callable一般是配合使用起来的。相比Runnable,Callable多了返回值,可以返回结果/异常,由Future对象接收。
executorCompletionService.submit(() -> {
task(number);
}, "任务" + number + "已完成");
}
long start = System.currentTimeMillis();
for (int i = 0; i < 5; i++) {
// poll队列的时候还没任务做完,所以返回null,这时候get()就空指针了
System.out.println(executorCompletionService.poll(2000, TimeUnit.MILLISECONDS).get());
System.out.println("耗时:" + (System.currentTimeMillis() - start));
}
}
/**
* get方法
* 如果任务没有完成,使用get()就会被阻塞,而且没有异常的处理方法,只能去在get的时候catch
*
* @param executorCompletionService
* @throws Exception
*/
private static void test4(ExecutorCompletionService<Object> executorCompletionService) throws Exception {
// 设置1个任务
Integer number = 1;
// Future和Callable一般是配合使用起来的。相比Runnable,Callable多了返回值,可以返回结果/异常,由Future对象接收。
Future<Object> future = executorCompletionService.submit(() -> {
task(number);
}, "任务" + number + "已完成");
System.out.println(future.get());
}
/**
* 执行的任务,任务1--1000ms,任务2--3000ms,其余任务10ms
*
* @param number
*/
public static void task(Integer number) {
try {
switch (number) {
case 0:
Thread.sleep(1000);
System.out.println("线程:" + Thread.currentThread().getName() + "执行任务0完成");
break;
case 1:
Thread.sleep(5000);
System.out.println("线程:" + Thread.currentThread().getName() + "执行任务1完成");
break;
default:
Thread.sleep(10);
System.out.println("线程:" + Thread.currentThread().getName() + "执行任务" + number + "完成");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}