您的位置:首页 > 编程语言 > Java开发

java并发编程:Callable、Future和FutureTask

2015-01-29 14:32 471 查看
1.问题引入

创建线程有2中方式:直接继承Thread和实现Runnable接口。但是这2种方式都有一个缺陷,那就是执行完任务之后无法获取执行结果。

如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,但这样使用起来非常麻烦。

所以,自从jdk1.5之后,就提供了Callable和Future,通过他们可以获得任务执行完毕之后得到任务的执行结果。

2.Callable和Runnable

先说一下Runnable接口,在其中只声明了一个run()方法

public interface Runnable
{
public abstract void run();
}
由于run()方法返回值为void类型,所以在执行完任务之后,无法返回任何结果。

Callable位于java.util.concurrent包下,也是一个接口,在里面也是只声明了一个方法:

public interface Callable<V>
{
V call() throws Exception;
}
可以看到,这是一个泛型接口,call()返回的类型就是传递进来的泛型

那么如何使用Callable呢?一般情况下需要配合ExecutorService,在ExecutorService接口中声明了若干个submit方法的重载版本

<T> Future<T> submit(Callable<T> task);

<T> Future<T> submit(Runnable task, T result);

Future<?> submit(Runnable task);
第一个submit方法里的参数类型就是Callable。一般我们使用第一和第三个方法

3.Future

Future就是对具体的Runnable或者Callable任务的结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果

Future位于java.util.concurrent包下:

public interface Future<V>
{
boolean cancel(boolean mayInterruptIfRunning);                //用来取消任务,参数表示是否能够取消正在执行却没有执行完成的任务

boolean isCancelled();                                       //用来表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回true

boolean isDone();                                              //表示任务是否已经完成,如果任务完成则返回true

V get() throws InterruptedException, ExecutionException;       //用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回

V get(long timeout, TimeUnit unit)                                //获取执行结果,如果在指定时间内还没有取到结果,就直接返回null
throws InterruptedException, ExecutionException, TimeoutException;
}
简单地说,Future提供了3种功能:

(1)中断任务 (2)判断任务是否完成 (3)获取任务执行结果

因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此有了下面的FutureTask

4.FutureTask

先看一下FutureTask的声明

public class FutureTask<V> implements RunnableFuture<V>
FutureTask实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现

public interface RunnableFuture<V> extends Runnable, Future<V>
{
void run();
}
可以看出FutureTask实现了RunnableFuture接口,RunnableFuture接口继承了Runnable和Future接口,所以FutureTask既可以作为线程执行,又可以作为Future得到Callable的返回值

FutureTask的构造器

public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;       // ensure visibility of callable
}

public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW;       // ensure visibility of callable
}
可以看出不论是使用Callable还是Runnable,最终都是转换为Callable

5.使用实例

(1)使用Callable+Future获取执行结果

class Task implements Callable<Integer>
{
@Override
public Integer call() throws Exception
{
System.out.println("sub thread is running");
Thread.sleep(3000);
int sum = 0;
for(int i=1; i<100; i++)
sum += i;
return sum;
}

}
public class TestFuture
{
public static void main(String[] args)
{
ExecutorService executorService = Executors.newCachedThreadPool();
Task task = new Task();
Future<Integer> result = executorService.submit(task);
executorService.shutdown();

try
{
Thread.sleep(1000);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
try
{
System.out.println(result.get());
}
catch (InterruptedException e)
{
e.printStackTrace();
}
catch (ExecutionException e)
{
e.printStackTrace();
}
}
结果为:

sub thread is running
4950


(2)使用Callable+FutureTask获取执行结果

public static void main(String[] args)
{
ExecutorService executorService = Executors.newCachedThreadPool();
Task task = new Task();
FutureTask<Integer> futureTask =new FutureTask<>(task);
executorService.submit(futureTask);
executorService.shutdown();

try
{
Thread.sleep(1000);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
try
{
System.out.println(futureTask.get());
}
catch (InterruptedException e)
{
e.printStackTrace();
}
catch (ExecutionException e)
{
e.printStackTrace();
}
}
结果与上面完全相同
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: