1:Future类
FutureTask叫未来任务,可以将一个复杂的任务剔除出去交给另外一个线程来完成
图示为main方法开始,依次调用多个方法。但是第3个方法复杂,为避免其是瓶颈影响整个程序效率,所以将其剔除出去交给FutureTask去完成,这样避免阻塞主线程。
2:Callable和Future的关系
可以用Future.get来获取Callable接口返回的执行结果,还可以通过Future.isDone()来判断任务是否已经执行完,以及取消这个任务,限时获取任务的结果等。
在call()未执行完毕前,调用get()的线程(假设此时是主线程)会被阻塞,直到call()方法返回结果后,此时future.get()才会得到该结果,然后主线程才会切换到runnable状态。
所以Future是一个存储器,它存储了call()这个任务的结果,而这个任务的执行时间是无法确定的,因为这完全取决于call()方法的执行情况。
3:Future主要方法
1:get()
get方法的行为取决于Callable任务的状态,只有以下5种情况:
1)任务正常完成:get方法会立刻返回结果
2)任务尚未完成(任务还没有开始或进行中):get将阻塞并直到任务完成。
3)任务执行过程中抛出Exception:get方法会抛出ExecutionException,这里抛出异常,是call()执行时产生的那个异常,
看到这个异常类型是java.util.concurrent.ExecutionException.不论call()执行时抛出的异常类型是什么,最后get方法会抛出的异常类型都是ExceutionException
4)任务被取消:get方法会抛出CancellationException
5)任务超时:get方法有一个重写方法,是传入一个延迟时间的,如果时间到了还没有获得结果,get方法会抛出TimeoutException
2:get(long timeout,TimeUnit unit)
如果call()在规定时间内完成任务,那么就会正常获取到返回值,而如果在指定时间内没有计算出结果,则会抛出TimeoutException
超时不获取,任务需要取消
3:cancel()
如果这个任务还没有开始执行,任务会被正常取消,未来也不会被执行,返回true
如果任务已经完成或已经取消,则cancel()方法会执行失败,方法返回false
如果这个任务已经开始,这个取消方法将不会直接取消该任务,而是会根据参数mayInterruptIfRunningg来做判断。如果是true,就会发出中断信号给这个任务。
4:isDone()
判断线程是否执行完,执行完并不代表执行成功。
5:isCancelled()
判断是否被取消
4:用线程池的submit方法返回Future对象
首先要给线程池提交任务,提交时线程池会立刻返回一个空的Future容器。当线程的任务一旦执行完,也就是当我们可以获取结果时,线程池会把该结果填入到之前给我们的那个Future中去(而不是创建一个新的Future),我们此时可以从该Future中获得任务执行的结果。
future/OneFuture.java
package future;
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;
/**
* 描述: 演示一个Future的使用方法
*/
public class OneFuture {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
Future<Integer> future = service.submit(new CallableTask());
try {
//等待3秒后打印
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
service.shutdown();
}
static class CallableTask implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Thread.sleep(3000);
return new Random().nextInt();
}
}
}
5:用FutureTask来创建Future
用FutureTask来获取Future和任务的结果。
FutureTask实现Runnable和Future接口
把Callable实例当作参数,生成FutureTask的对象,然后把这个对象当作一个Runnable对象,用线程池去执行这个Runnable对象,最后通过FutureTask获取刚才执行的结果。
future/ FutureTaskDemo.java
package future;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
/**
* 描述: 演示FutureTask的用法
*/
public class FutureTaskDemo {
public static void main(String[] args) {
Task task = new Task();
//FutureTask继承Future和Runnalbe接口
FutureTask<Integer> integerFutureTask = new FutureTask<>(task);
// new Thread(integerFutureTask).start();
ExecutorService service = Executors.newCachedThreadPool();
service.submit(integerFutureTask);
try {
System.out.println("task运行结果:"+integerFutureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class Task implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("子线程正在计算");
Thread.sleep(3000);
//模拟子线程处理业务逻辑
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
return sum;
}
}