
上次介绍了Callable实现多线程的方法。现在介绍和Callable搭配的类。上一篇只是简单的用Callable做了一个demo。
一、Future
1.关于callable和runable的区别(上次已经介绍)
Callable可以在任务结束的时候提供一个返回值Future对象,Runnable无法提供这个功能
Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。
Callable规定的方法是call(),而Runnable规定的方法是run().
2.Future介绍
Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
Future类位于java.util.concurrent包下,它是一个接口:
public interface Future<V> {
boolean cancel( boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get( long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
} |
在Future接口中声明了5个方法,下面依次解释每个方法的作用:
- cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
- isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
- isDone方法表示任务是否已经完成,若任务完成,则返回true;
- get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
- get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
也就是说Future提供了三种功能:
1)判断任务是否完成;
2)能够中断任务;
3)能够获取任务执行结果。
因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了FutureTask。
3.测试
public class TestCallable {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
Task task = new Task();
Future<Integer> result = executor.submit(task);
executor.shutdown();
try {
Thread.sleep( 1000 );
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println( "主线程在执行任务" );
try {
System.out.println( "task运行结果" +result.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println( "所有任务执行完毕" );
}
} 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;
}
} |
结果:
子线程在进行计算
主线程在执行任务
task运行结果4950
所有任务执行完毕
二、FutureTask
1.FutureTask的实现
public
class
FutureTask<V>
implements
RunnableFuture<V>
FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:
public
interface
RunnableFuture<V>
extends
Runnable, Future<V> {
void
run();
}
可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。
也就是说:
FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。
FutureTask实现了Futrue可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。
FutureTask提供了2个构造器:
public
FutureTask(Callable<V> callable) {
}
public
FutureTask(Runnable runnable, V result) {
}
FutureTask是Future接口的一个实现类(唯一的实现类)。
2.测试
public class FutureTaskTest {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
newTask task = new newTask();
FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
executor.submit(futureTask);
executor.shutdown();
try {
Thread.sleep( 1000 );
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println( "主线程在执行任务" );
try {
System.out.println( "task运行结果" + futureTask.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println( "所有任务执行完毕" );
}
} class newTask 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;
}
} |
结果:
子线程在进行计算
主线程在执行任务
task运行结果4950
所有任务执行完毕