java.util.concuttent Callable Future详解

在传统的多线程实现方式中(继承Thread和实现Runnable)没法直接获取线程执行的返回结果,若是须要获取执行结果,就必须经过共享变量或者使用线程通讯的方式来达到效果,这样使用起来就比较麻烦。java

从Java 1.5开始,java.util.concurrent包中提供了 Callable和 Future两个接口,经过它们就能够在任务执行完毕以后获得任务执行结果。程序员

Callable

Callable与Runnable的功能大体类似,Callable中有一个call()函数,可是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。多线程

Future

Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行框架

取消、查询是否完成、获取结果、设置结果操做。get方法会阻塞,直到任务返回结果。dom

 

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;
}
  • 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提供了三种功能:异步

  • 判断任务是否完成
  • 可以中断任务
  • 可以获取任务的执行结果

Future和FutureTask区别

Future是一个接口,  FutureTask类是Future 的一个实现类,并实现了Runnable,所以FutureTask能够传递到线程对象Thread中新建一个线程执行。因此可经过Excutor(线程池) 来执行,也可传递给Thread对象执行。若是在主线程中须要执行比较耗时的操做时,但又不想阻塞主线程时,能够把这些做业交给Future对象在后台完成,当主线程未来须要时,就能够经过Future对象得到后台做业的计算结果或者执行状态。 

FutureTask是为了弥补Thread的不足而设计的,它可让程序员准确地知道线程何时执行完成并得到到线程执行完成后返回的结果(若是有须要)。ide

FutureTask是一种能够取消的异步的计算任务。它的计算是经过Callable实现的,它等价于能够携带结果的Runnable,而且有三个状态:等待、运行和完成。完成包括全部计算以任意的方式结束,包括正常结束、取消和异常。函数

Executor框架利用FutureTask来完成异步任务,并能够用来进行任何潜在的耗时的计算。通常FutureTask多用于耗时的计算,主线程能够在完成本身的任务后,再去获取结果。测试

FutureTask多用于耗时的计算,主线程能够在完成本身的任务后,再去获取结果线程

Example1

package cn.com.example.concurrent.future;

import java.util.concurrent.*;

/**
 * Created by Jack on 2017/1/24.
 */
public class RunnableFutureTask {

    /**
     * ExecutorService
     */
    static ExecutorService mExecutor = Executors.newSingleThreadExecutor();

    /**
     * @param args
     */
    public static void main(String[] args) {
        runnableDemo();
        futureDemo();
    }

    /**
     * runnable, 无返回值
     */
    static void runnableDemo() {

        new Thread(new Runnable() {

            @Override
            public void run() {
                System.out.println("runnable demo : " + fibc(20));
            }
        }).start();
    }

    /**
     * 其中Runnable实现的是void run()方法,无返回值;Callable实现的是 V
     * call()方法,而且能够返回执行结果。其中Runnable能够提交给Thread来包装下
     * ,直接启动一个线程来执行,而Callable则通常都是提交给ExecuteService来执行。
     */
    static void futureDemo() {
        try {
            /**
             * 提交runnable则没有返回值, future没有数据
             */
            Future<?> result = mExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    fibc(20);
                }
            });

            System.out.println("future result from runnable : " + result.get());

            /**
             * 提交Callable, 有返回值, future中可以获取返回值
             */
            Future<Integer> result2 = mExecutor.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    return fibc(20);
                }
            });

            System.out.println("future result from callable : " + result2.get());

            /**
             * FutureTask则是一个RunnableFuture<V>,即实现了Runnbale又实现了Futrue<V>这两个接口,
             * 另外它还能够包装Runnable(实际上会转换为Callable)和Callable
             * <V>,因此通常来说是一个符合体了,它能够经过Thread包装来直接执行,也能够提交给ExecuteService来执行
             * ,而且还能够经过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。
             */
            FutureTask<Integer> futureTask = new FutureTask<Integer>(
                    new Callable<Integer>() {
                        @Override
                        public Integer call() throws Exception {
                            return fibc(20);
                        }
                    });
            // 提交futureTask
            mExecutor.submit(futureTask);
            System.out.println("future result from futureTask : " + futureTask.get());

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
     * 效率底下的斐波那契数列, 耗时的操做
     *
     * @param num
     * @return
     */
    static int fibc(int num) {
        if (num == 0) {
            return 0;
        }
        if (num == 1) {
            return 1;
        }
        return fibc(num - 1) + fibc(num - 2);
    }

}

结果:

runnable demo : 6765
future result from runnable : null
future result from callable : 6765
future result from futureTask : 6765

Example2:

package cn.com.example.concurrent.future;

import java.util.Random;
import java.util.concurrent.*;

/**
 * Created by Jack on 2017/1/24.
 */
public class RunnableFutureTask {

    public static void main(String[] args) {
        // 初始化一个Callable对象和FutureTask对象
        Callable pAccount = new PrivateAccount();
        FutureTask futureTask = new FutureTask(pAccount);
        // 使用futureTask建立一个线程
        Thread pAccountThread = new Thread(futureTask);
        System.out.println("futureTask线程如今开始启动,启动时间为:" + System.nanoTime());
        pAccountThread.start();
        System.out.println("主线程开始执行其余任务");
        // 从其余帐户获取总金额
        int totalMoney = new Random().nextInt(100000);
        System.out.println("如今你在其余帐户中的总金额为" + totalMoney);
        System.out.println("等待私有帐户总金额统计完毕...");
        // 测试后台的计算线程是否完成,若是未完成则等待
        while (!futureTask.isDone()) {
            try {
                Thread.sleep(500);
                System.out.println("私有帐户计算未完成继续等待...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("futureTask线程计算完毕,此时时间为" + System.nanoTime());
        Integer privateAccountMoney = null;
        try {
            privateAccountMoney = (Integer) futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("您如今的总金额为:" + totalMoney + privateAccountMoney.intValue());
    }
}

class PrivateAccount implements Callable {
    Integer totalMoney;

    @Override
    public Object call() throws Exception {
        Thread.sleep(5000);
        totalMoney = new Integer(new Random().nextInt(10000));
        System.out.println("您当前有" + totalMoney + "在您的私有帐户中");
        return totalMoney;
    }

}

结果:

futureTask线程如今开始启动,启动时间为:88171383410225
主线程开始执行其余任务
如今你在其余帐户中的总金额为2838
等待私有帐户总金额统计完毕...
私有帐户计算未完成继续等待...
私有帐户计算未完成继续等待...
私有帐户计算未完成继续等待...
私有帐户计算未完成继续等待...
私有帐户计算未完成继续等待...
私有帐户计算未完成继续等待...
私有帐户计算未完成继续等待...
私有帐户计算未完成继续等待...
私有帐户计算未完成继续等待...
您当前有9238在您的私有帐户中
私有帐户计算未完成继续等待...
futureTask线程计算完毕,此时时间为88176389195218
您如今的总金额为:28389238
相关文章
相关标签/搜索