Future和Callable
public class FutureTest {
static class Task implements Callable{
@Override
public Object call() throws Exception {
Thread.sleep(3000);
return "<html><h1>Hello World</h1></html>";
}
}
public static void main(String...args) throws ExecutionException, InterruptedException {
Callable task = new Task();
ExecutorService service = Executors.newFixedThreadPool(3);
Future<String> future = service.submit(task);
service.shutdown();
System.out.println(System.currentTimeMillis());
System.out.println(future.get());
System.out.println(System.currentTimeMillis());
}
}
/*
1505622184281
<html><h1>Hello World</h1></html>
1505622187281
*/
Future的缺点:Future接口调用get()方法是堵塞的,也就是如果任务未完成则会堵塞并等待完成。并且有多个任务时,当调用最耗时的任务的get()时,会等待过久的时间。但此时可能别的任务已经完成了,但我们不能做任何事情。
CompletionService
以异步的方式,一边生产新的任务,一边处理已完成任务的结果。最先完成的任务,会被最先处理,所以能解决Future的问题。
public class CompletionServiceTest {
static class MyCallable implements Callable<String>{
private String username;
private long sleepValue;
public MyCallable(String username, long sleepValue) {
this.username = username;
this.sleepValue = sleepValue;
}
@Override
public String call() throws Exception {
System.out.println(username);
Thread.sleep(sleepValue);
return "return "+username;
}
}
public static void main(String...args){
try {
MyCallable c1 = new MyCallable("username1",5000);
MyCallable c2 = new MyCallable("username2",4000);
MyCallable c3 = new MyCallable("username3",3000);
MyCallable c4 = new MyCallable("username4",2000);
MyCallable c5 = new MyCallable("username5",1000);
List<Callable> list = new ArrayList<>();
list.add(c1);
list.add(c2);
list.add(c3);
list.add(c4);
list.add(c5);
ThreadPoolExecutor executor
= new ThreadPoolExecutor(5,10,5, TimeUnit.SECONDS,
new LinkedBlockingDeque<>());
CompletionService csRef = new ExecutorCompletionService(executor);
for (int i = 0;i < 5;i++){
csRef.submit(list.get(i));
}
executor.shutdown();
for (int i = 0;i < 5;i++){
System.out.println("等待打印"+(i+1)+"个返回值");
System.out.println(csRef.take().get());
}
}catch (Exception r){}
}
}
/*
username1
username4
username3
username2
username5
等待打印1个返回值
return username5
等待打印2个返回值
return username4
等待打印3个返回值
return username3
等待打印4个返回值
return username2
等待打印5个返回值
return username1
*/
take()会取得最先完成任务的Future对象,如果没有则堵塞等待。
poll()会获取并移除下一个已完成任务的Future,如果不存在已完成的任务,则返回null,不会阻塞。
ExecutorService
invokeAny()会堵塞,并获取在一大堆Callable中取得最先完成的任务,然后返回。但是其他任务还是会继续运行,不会停止。但是会将线程interrupt标志设置为true,线程可以选择处理来停止任务。
invokeAll()会堵塞,并等待全部任务都完成,并返回所有任务的执行结果。
ScheduledExecutorService
将定时任务和线程池功能结合使用。
Fork-Join
ForkJoinPool提供了一个任务池,但执行任务的是ForkJoinTask类,ForkJoinTask是个抽象类,有三个抽象子类:CountedCompleter, RecursionAction, RecursiveTask。
三个抽象子类实现了除compute()的别的方法,所以,我们的任务就是继承并重写这个方法。
执行任务
public class ForkJoinTest {
static class MyRecursiveAction extends RecursiveAction{
@Override
protected void compute() {
System.out.println("Computer");
}
}
public static void main(String...args) throws InterruptedException {
ForkJoinPool pool = new ForkJoinPool();
pool.submit(new MyRecursiveAction());
Thread.sleep(20);
}
}
分解任务
public class ForkJoinTest {
static class MyRecursiveAction extends RecursiveAction{
private int beginValue;
private int endValue;
public MyRecursiveAction(int beginValue, int endValue) {
this.beginValue = beginValue;
this.endValue = endValue;
}
@Override
protected void compute() {
//System.out.println("---"+Thread.currentThread()+"---");
if (endValue - beginValue > 2){
int middle = (beginValue + endValue)/2;
MyRecursiveAction left = new MyRecursiveAction(beginValue,middle);
MyRecursiveAction right = new MyRecursiveAction(middle+1,endValue);
this.invokeAll(left,right);
}else{
System.out.println("打印组合为:"+beginValue+"-"+endValue);
}
}
}
public static void main(String...args) throws InterruptedException {
ForkJoinPool pool = new ForkJoinPool();
pool.submit(new MyRecursiveAction(1,100));
pool.awaitQuiescence(5, TimeUnit.SECONDS);
}
}
/*
打印组合为:76-77
打印组合为:78-79
打印组合为:1-2
打印组合为:64-66
打印组合为:51-52
打印组合为:58-60
打印组合为:61-63
打印组合为:14-16
打印组合为:17-19
......
*/