并发编程实战(4). 异步任务 之 Callable,Future,FutureTask

Java 中异步任务的实现 之 Callable,Future,FutureTask

这里,我们主要用到的类和接口为:Callable,Future,FutureTask

Runable只需关心运行的动作行为,而Callable同时关心运行的结果。

package java.util.concurrent;
@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

Future表示一个任务的生命周期。提供接口来判断任务完成,取消与否,也提供接口来获取任务结果。

get方法的行为取决于任务的状态(尚未开始,正在运行,已完成)

  • 如果任务已经完成,那么get会立即返回结果或者抛出异常(任务执行过程中发生异常、任务被取消也属于任务已完成 )
  • 如果任务没有完成,get将阻塞。
  • 如果任务抛出异常,那么get会将该异常封装为ExecutionException重新抛出,可以通过getCause来获取最初的异常
  • 如果任务被取消,那么get将抛出CancellationException
package 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任务

  • ExecutorService中所有submit方法都返回一个Future。
  • 指定Runnable或者Callable实例化一个FutureTask(FutureTask实现了Runnable,因此可以将它提交给Executor来执行,或者直接调用它的run方法)

我们简单看看FutureTask的代码:

public class FutureTask<V> implements RunnableFuture<V> {
    // 这里不列出它的代码了
}

// 其中RunnableFuture接口:
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

下面来测试一个Future代码例子,体验一下异步任务:

@Slf4j
public class FutureExample {
    
    /**
    * 定义自己的Callable实现
    * 它描述了任务怎么执行,以及执行的返回结果
    */
    static class MyCallable implements Callable<String> {

        @Override
        public String call() throws Exception {
            log.info("do something in callable");
            // 异步任务执行5秒钟
            Thread.sleep(5000);
            return "Done";
        }
    }

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        // 提交Callable到ExecutorService,会返回一个Future
        Future<String> future = executorService.submit(new MyCallable());
        log.info("do something in main");
        // 主任务提交任务后执行1秒钟,然后通过get等待执行结果
        Thread.sleep(1000);
        String result = future.get();
        log.info("result:{}", result);
    }
}

// 顺带讨论一下Lambda表达式怎么简化程序代码:
@Slf4j
public class FutureExample {
	public static void main(String[] args) throws Exception {
       ExecutorService executorService = Executors.newCachedThreadPool();
       Future<String> future = executorService.submit( ()->{ // Callable
                                   log.info("do something in callable");
                                   Thread.sleep(5000);
                                   return "Done";
                               });
       log.info("do something in main");
       Thread.sleep(1000);
       String result = future.get();
       log.info("result:{}", result);
	}
}

我们运行,看一看运行结果如下,可以看到,43秒开始等待运行结果,5秒后的48秒返回结果"Done"

11:46:43.086 [pool-1-thread-1] INFO FutureExample - do something in callable
11:46:43.086 [main] INFO FutureExample - do something in main
11:46:48.092 [main] INFO FutureExample - result:Done

同样,我们使用FutureTask也能达到同样的效果:

@Slf4j
public class FutureTaskExample {

    public static void main(String[] args) throws Exception {
        FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                log.info("do something in callable");
                Thread.sleep(5000);
                return "Done";
            }
        });

        new Thread(futureTask).start();
        log.info("do something in main");
        Thread.sleep(1000);
        String result = futureTask.get();
        log.info("result:{}", result);
    }
}
// 同样,我们尝试Lambda表达式重写一下:
@Slf4j
public class FutureTaskExample {

    public static void main(String[] args) throws Exception {
        FutureTask<String> futureTask = new FutureTask<>(()->{
                                            log.info("do something in callable");
                                            Thread.sleep(5000);
                                            return "Done";
                                        });
        new Thread(futureTask).start();
        log.info("do something in main");
        Thread.sleep(1000);
        String result = futureTask.get();
        log.info("result:{}", result);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章