Java 异步调用及Callable, Future, FutureTask 原理

一 、使用方式一般为两种:

1 . 创建线程执行FutureTask并通过FutureTask得到异步结果;

public static void main(String[] args) throws ExecutionException, InterruptedException {

        long start = System.currentTimeMillis();

        // 1.创建任务,这个FutureTask可以是Callable的也可以是Runnable的
        FutureTask task = new FutureTask(new Callable() {
            @Override
            public Object call() throws Exception {
                Thread.sleep(3000); // 模拟异步任务执行
                return "我是异步结果";
            }
        });

        // 2.创建线程执行任务
        Thread thread = new Thread(task);
        thread.start();

        // 3.主线程模拟在异步任务之间执行其他任务
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 4.得到异步任务结果
        System.out.println(task.get());

        System.out.println("运行时间 : " + (System.currentTimeMillis() - start) + "ms");
    }

运行结果:

我是异步结果
运行时间 : 6002ms

Process finished with exit code 0

 

2 . 使用线程池管理线程通过Future接口得到结果;

public static void main(String[] args) throws ExecutionException, InterruptedException {

        long start = System.currentTimeMillis();

        ExecutorService executorService = Executors.newFixedThreadPool(5);

        Future future = executorService.submit(new Callable() {
            @Override
            public Object call() throws Exception {
                Thread.sleep(3000);
                return "我是异步结果";
            }
        });

        System.out.println("主线程工作");
        Thread.sleep(6000);

        System.out.println(future.get());

        System.out.println("运行时间 : " + (System.currentTimeMillis() - start) + "ms");
    } 
  

 运行结果:

主线程工作
我是异步结果
运行时间 : 6012ms 

 

注意:

        异步结果用Future或者FutureTask都可以获取。Future是接口,FutureTask是实现了这个接口的实现类。FutureTask除了实现Future接口外,还实现了Runnable接口。所以不论是Callable任务还是Runnable任务都可以用FutureTask完成,而这两种都会最终都会调用Callable的call方法,对于Runnable实现调用call的方式是使用了适配器模式。

Java 异步调用及Callable, Future, FutureTask 原理_第1张图片 (图片来源网上,侵删)

      debug第二个程序,我们可以看到这时定义的Future也是FutureTask实现的。

Java 异步调用及Callable, Future, FutureTask 原理_第2张图片

二、异步原理

1.  异步模型:

         可以总结为生产者和消费者,生产者就是线程处理任务,消费者就是调用者得到任务结果。那生产者消费者模型还有缓冲区啊,这里面就是用FutureTask中的outcome字段在任务结束后缓存结果。

2 . 异步流程:

         主线程main开启线程a执行任务,并马上返回Future,如果是刚新建任务,状态置为new。当main线程想取线程a执行的结果(调用了FutureTask的get方法)时,就查看这个任务的state是否执行完成(completing),如果还没有完成就阻塞当前线程(main)等待线程a执行完成。

 

 

 

你可能感兴趣的:(线程,Java)