Java任务与返回结果Runnable、Callable、Future、FutureTask

在Java中,Runnable、Callable都表示能被线程执行的任务。

Runnable有以下缺陷:

    1、没有返回值 

    2、不能抛出checked exception

Callable接口类似于Runnable,但能返回一个结果,也可以抛出Exception,使用者需要实现call()方法。

/**
 * Callable接口源码
 */
@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

Future是一个存储器,存储了Callable的返回结果。

ExecutorService提交任务的部分方法如下

     void execute(Runnable command);     execute方法只能接收Runnable任务,没有返回值。

     <T> Future<T> submit(Callable<T> task);     submit方法接收Callable任务,返回结果保存在Future中。

     Future<?> submit(Runnable task);      submit方法也可接收Runnable任务,返回结果保存在Future中。由于Runnable没有返回值,Future中保存的结果是null。

Future的方法

    boolean    cancel(boolean mayInterruptIfRunning)   尝试取消此任务的执行。

    V    get()  获取任务结果

    V    get(long timeout, TimeUnit unit)  限时获取任务结果

    boolean    isCancelled()  取消任务

    boolean    isDone()   如果任务完成,返回true。

get()方法获取结果有5种情况

    1、任务正常完成,get()方法会立刻返回结果。

    2、任务尚未完成(任务未开始或进行中),get()将阻塞并直到任务完成。

    3、任务执行过程中抛出Exception,get()方法会抛出ExecutionException;不论call()执行时抛出什么异常,最后get()方法抛出的异常类型都是ExecutionException。

    4、任务被取消,get方法会抛出CancellationException。

    5、任务超时,get方法有一个重载方法,可以传入延迟时间,如果时间到了还没有获得结果,get方法会抛出TimeoutException。

class Future0{

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 线程池execute方法执行Runnable任务
        executorService.execute(new Task());

        // 线程池submit方法执行Runnable任务
        Future f = executorService.submit(new Task());
        try {
            Object data = f.get();
            // 使用submit(Runnable task); future.get()返回null
            System.out.println("submit(Runnable task)得到的future.get()   "+data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        /**
         * 线程池submit方法执行Callable任务
         * 执行submit方法时,线程池立刻返回一个空的Future容器,当线程的任务一旦执行完毕,线程池会把结果填入Future中
         */
        Future<Integer> future = executorService.submit(new CallableTask());
        try {
            /**
             * 任务正常完成,get()方法会立刻返回结果。
             * 任务尚未完成(任务未开始或进行中),get()将阻塞并直到任务完成。
             */
            Integer data = future.get();
            System.out.println("submit(Callable<T> task)得到的future.get()   "+data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        executorService.shutdown();
    }

    static class Task implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"run()运行");
        }
    }

    static class CallableTask implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            TimeUnit.SECONDS.sleep(2);
            return new Random().nextInt(10);
        }
    }

}
/**
 * Callable抛出异常时,主线程不会抛异常,直到执行future.get()的时候才会抛异常
 * 不论call()执行抛出什么异常,最后get()方法抛出的异常类型都是ExecutionException。
 */
class Future01{
    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Future<Object> future = executorService.submit(() -> {
            throw new IllegalArgumentException("在Callable中抛出IllegalArgumentException异常");
        });

        TimeUnit.SECONDS.sleep(1);

        System.out.println("任务是否全部运行完毕。"+future.isDone());

        try {
            Object o = future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("抛出InterruptedException");
        } catch (ExecutionException e) {
            e.printStackTrace();
            // System.out.println(e.getCause().getMessage());
            System.out.println("抛出ExecutionException");
        }

        executorService.shutdown();
    }
}
/**
 * 超时与取消任务演示
 * 
 * cancel方法,取消任务
 *     1、如果任务还没开始执行,任务会被取消,未来也不会被执行,返回true。
 *     2、如果任务已完成或已取消,cancel方法会执行失败,返回false。
 *     3、如果任务正在执行,根据cancel(boolean mayInterruptIfRunning)参数取消任务,true取消,false不取消。
 * cancel(true)适用于能处理interrupt的任务
 * cancel(false)适用于。
 *     1、不能处理interrupt的任务,或者调用者不确定任务能否处理interrupt。
 *     2、需要等待已经开始的任务执行完成。
 */
class Future02{
    private static final ExecutorService exec = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        Future<Ad> future = exec.submit(() -> {

            //TimeUnit.MILLISECONDS.sleep(1000);

            // 任务超时演示
            TimeUnit.MILLISECONDS.sleep(3000);

            return new Ad("某程的旅游广告");
        });

        Ad ad;
        try {
            ad = future.get(2000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            ad = new Ad("发生中断的默认广告");
        } catch (ExecutionException e) {
            ad = new Ad("异常时的默认广告");
        } catch (TimeoutException e) {
            ad = new Ad("超时的默认广告");
            System.out.println("超时,执行取消任务");
            boolean cancel = future.cancel(true);
            System.out.println("cancel的结果:"+cancel);
        }

        System.out.println(ad);

        exec.shutdown();
    }

    static class Ad{
        String name;
        public Ad(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Ad{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    
}

还有一个常用的类FutureTask,FutureTask实现了RunnableFuture,RunnableFuture同时继承了Runnable、Future接口,在Java中,接口可以多实现。

FutureTask是一种包装器,其中的一个构造函数是接受Callable类型的参数,既可以作为Callable被线程执行,又可以作为Future得到Callable的返回结果。

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

FutureTask类图如下

class FutureTask1{
    static ExecutorService service = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        // 创建Callable对象
        Callable callable = () -> {
            System.out.println("子线程正在计算");
            TimeUnit.SECONDS.sleep(1);
            int sum = 0;
            for (int i = 0; i < 100; i++) {
                sum += i;
            }
            return sum;
        };

        // 使用Callable创建FutureTask
        FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);

        // 线程池提交FutureTask
        service.submit(futureTask);

        try {
            System.out.println("FutureTask运行结果"+futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        service.shutdown();
    }
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值