Java Callable Future 示例

Java Callable 和 Future 在多线程编程中被广泛使用。在最近的几篇文章中,我们学到了很多关于 Java 线程,但有时我们希望线程能够返回我们可以使用的某个值。Java 5 引入了 java.util.concurrent.Callable 接口,它位于并发包中,类似于 Runnable 接口,但它可以返回任何对象并且能够抛出异常。

Java Callable

Java Callable 接口使用泛型来定义对象的返回类型。Executors 类提供了在线程池中执行 Java Callable 的实用方法。由于可调用任务是并行运行的,我们必须等待返回的对象。

Java Future

Java Callable任务返回java.util.concurrent.Future对象。使用Java Future对象,我们可以查找Callable任务的状态并获取返回的对象。它提供了get()方法,可以等待Callable完成并返回结果。Java Future提供了cancel()方法来取消关联的Callable任务。还有一个重载版本的get()方法,我们可以指定等待结果的时间,这对于避免当前线程被阻塞更长时间是有用的。还有isDone()isCancelled()方法来查找关联Callable任务的当前状态。这里是一个简单的Java Callable任务的示例,在一秒钟后返回执行任务的线程的名称。我们使用Executor框架并行执行100个任务,并使用Java Future来获取提交任务的结果。

package com.journaldev.threads;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MyCallable implements Callable {

    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        //返回执行此可调用任务的线程名称
        return Thread.currentThread().getName();
    }
    
    public static void main(String args[]){
        //从Executors实用类获取ExecutorService,线程池大小为10
        ExecutorService executor = Executors.newFixedThreadPool(10);
        //创建一个列表来保存与Callable关联的Future对象
        List> list = new ArrayList>();
        //创建MyCallable实例
        Callable callable = new MyCallable();
        for(int i=0; i< 100; i++){
            //提交要由线程池执行的可调用任务
            Future future = executor.submit(callable);
            //将Future添加到列表中,我们可以使用Future获取返回值
            list.add(future);
        }
        for(Future fut : list){
            try {
                //打印Future的返回值,请注意控制台中的输出延迟
                //因为Future.get()等待任务完成
                System.out.println(new Date()+ "::"+fut.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        //现在关闭执行器服务
        executor.shutdown();
    }

}

执行上述程序后,您会注意到输出延迟,因为java Future get()方法等待java callable任务完成。还要注意,只有10个线程执行这些任务。以下是上述程序输出的片段。

Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
...

提示:如果我们想要重写Java Future接口的某些方法,例如重写get()方法以在一些默认时间后超时而不是无限期等待,那么Java FutureTask类就派上用场了,它是Future接口的基本实现。查看Java FutureTask示例以了解有关此类的更多信息。

Source:
https://www.digitalocean.com/community/tutorials/java-callable-future-example