范例1:线程池多任务先完成先返回处理结果
package com.contoso;
import java.util.Random;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CompletionServiceExample1 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Random random = new Random();
ExecutorService executorService = Executors.newFixedThreadPool(10);
// CompletionService内部实现使用了blockingQueue<Future<V>>存储已经完成任务的执行结果
CompletionService<String> service = new ExecutorCompletionService(executorService);
for (int i = 1; i <= 10; i++) {
final int index = i;
service.submit(() -> {
long start = System.nanoTime();
Thread.sleep(random.nextInt(5000));
System.out.println(Thread.currentThread().getName() + "|任务正在处理中 ...");
long end = System.nanoTime();
double timeTaken = (end - start) / 1e9;
return String.valueOf(Thread.currentThread().getName() + " Task" + index + " Taken in seconds:" + timeTaken);
});
}
for (int j = 1; j <= 10; j++) {
long start = System.nanoTime();
//没有完成的任务在这一行代码这里会出现阻塞,耗时最少任务的处理结果先从take里面出来
Future<String> take = service.take();
long end = System.nanoTime();
double timeTaken = (end - start) / 1e9;
System.out.println("主线程打印没有完成的任务被阻塞的时间(单位:秒)" + timeTaken);
String result = take.get(); // 这一行代码在这里不会阻塞,引入放入队列中的都是已经完成的任务
System.out.println("主线程打印返回任务的处理时间:" + result + "\n");
}
executorService.shutdown();
System.out.println("所有任务已经完成,关闭线程池");
}
}
run:
pool-1-thread-5|任务正在处理中 ...
主线程打印没有完成的任务被阻塞的时间(单位:秒)0.126341778
主线程打印返回任务的处理时间:pool-1-thread-5 Task5 Taken in seconds:0.12415651
pool-1-thread-1|任务正在处理中 ...
主线程打印没有完成的任务被阻塞的时间(单位:秒)1.199077737
主线程打印返回任务的处理时间:pool-1-thread-1 Task1 Taken in seconds:1.325494439
pool-1-thread-7|任务正在处理中 ...
主线程打印没有完成的任务被阻塞的时间(单位:秒)1.073619992
主线程打印返回任务的处理时间:pool-1-thread-7 Task7 Taken in seconds:2.39895914
pool-1-thread-6|任务正在处理中 ...
主线程打印没有完成的任务被阻塞的时间(单位:秒)0.027563512
主线程打印返回任务的处理时间:pool-1-thread-6 Task6 Taken in seconds:2.426902391
pool-1-thread-2|任务正在处理中 ...
主线程打印没有完成的任务被阻塞的时间(单位:秒)0.494719977
主线程打印返回任务的处理时间:pool-1-thread-2 Task2 Taken in seconds:2.921960165
pool-1-thread-4|任务正在处理中 ...
主线程打印没有完成的任务被阻塞的时间(单位:秒)0.538435259
主线程打印返回任务的处理时间:pool-1-thread-4 Task4 Taken in seconds:3.46030321
pool-1-thread-8|任务正在处理中 ...
主线程打印没有完成的任务被阻塞的时间(单位:秒)0.201699418
主线程打印返回任务的处理时间:pool-1-thread-8 Task8 Taken in seconds:3.661973811
pool-1-thread-3|任务正在处理中 ...
主线程打印没有完成的任务被阻塞的时间(单位:秒)0.012382544
主线程打印返回任务的处理时间:pool-1-thread-3 Task3 Taken in seconds:3.674586569
pool-1-thread-9|任务正在处理中 ...
主线程打印没有完成的任务被阻塞的时间(单位:秒)0.767456447
主线程打印返回任务的处理时间:pool-1-thread-9 Task9 Taken in seconds:4.442219117
pool-1-thread-10|任务正在处理中 ...
主线程打印没有完成的任务被阻塞的时间(单位:秒)0.015987835
主线程打印返回任务的处理时间:pool-1-thread-10 Task10 Taken in seconds:4.458432685
所有任务已经完成,关闭线程池
BUILD SUCCESSFUL (total time: 4 seconds)
范例2:线程池多任务先完成先返回处理结果(等价于范例1的效果,但是代码太复杂啦)
package com.contoso;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
*
* future.get()
* future.get(long timeout, TimeUnit)
*/
public class ExecutorServiceExample2 {
public static void main(String[] args) {
int taskCount = 10;
ExecutorService executor = Executors.newFixedThreadPool(taskCount);
List<Future<String>> listFuture = new ArrayList();
for (int i = 1; i <= taskCount; i++) {
Future<String> future = executor.submit(new MyTask(5000, i));
listFuture.add(future);
}
while (taskCount > 0) {
for (Future<String> future : listFuture) {
String data = null;
try {
data = future.get(0, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
// 必须忽略超时异常,只要任务没有完成且等待时间为0就会报超时异常
// e.printStackTrace();
}
if (data != null) {
System.out.println("主线程打印返回任务的处理时间:" + data);
listFuture.remove(future);
taskCount--;
break;
}
}
}
executor.shutdown();
System.out.println("所有任务已经完成,关闭线程池");
}
}
class MyTask implements Callable<String> {
private int sleep;
private int indexTask;
Random random = new Random();
public MyTask(int sleep, int indexTask) {
this.sleep = sleep;
this.indexTask = indexTask;
}
@Override
public String call() throws Exception {
long start = System.nanoTime();
Thread.sleep(random.nextInt(sleep));// 模拟任务的执行时间
String data = Thread.currentThread().getName() + " Task" + indexTask + " Taken in seconds:";
long end = System.nanoTime();
double timeTaken = (end - start) / 1e9;
System.out.println(Thread.currentThread().getName() + "|任务已处理完成");
return timeTaken + " " + data;
}
}
run:
pool-1-thread-1|任务已处理完成
主线程打印返回任务的处理时间:0.009673773 pool-1-thread-1 Task1 Taken in seconds:
pool-1-thread-8|任务已处理完成
主线程打印返回任务的处理时间:1.051098125 pool-1-thread-8 Task8 Taken in seconds:
pool-1-thread-6|任务已处理完成
主线程打印返回任务的处理时间:1.24212383 pool-1-thread-6 Task6 Taken in seconds:
pool-1-thread-2|任务已处理完成
主线程打印返回任务的处理时间:1.404322572 pool-1-thread-2 Task2 Taken in seconds:
pool-1-thread-7|任务已处理完成
主线程打印返回任务的处理时间:1.432703838 pool-1-thread-7 Task7 Taken in seconds:
pool-1-thread-4|任务已处理完成
主线程打印返回任务的处理时间:1.986656899 pool-1-thread-4 Task4 Taken in seconds:
pool-1-thread-10|任务已处理完成
主线程打印返回任务的处理时间:2.530709176 pool-1-thread-10 Task10 Taken in seconds:
pool-1-thread-3|任务已处理完成
主线程打印返回任务的处理时间:2.846413616 pool-1-thread-3 Task3 Taken in seconds:
pool-1-thread-9|任务已处理完成
主线程打印返回任务的处理时间:4.403490409 pool-1-thread-9 Task9 Taken in seconds:
pool-1-thread-5|任务已处理完成
主线程打印返回任务的处理时间:4.542559891 pool-1-thread-5 Task5 Taken in seconds:
所有任务已经完成,关闭线程池
BUILD SUCCESSFUL (total time: 4 seconds)