java并发编程:Callable、Future和FutureTask

本文介绍了Java并发编程中Callable和Future的使用方法,对比了Runnable接口,并详细解释了如何利用Callable结合Future来获取线程执行结果。

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();
		}
	}
         结果与上面完全相同

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值