在 Java 中,Callable
和 Future
是用于支持并发编程的关键接口,主要用于执行异步任务并获取任务的执行结果。
Callable
接口:
Callable
接口类似于Runnable
接口,不同之处在于Callable
接口的call()
方法可以返回执行结果,并且可以抛出异常。Callable
接口定义如下:
public interface Callable<V> {
V call() throws Exception;
}
Callable
接口通常使用 ExecutorService
来提交执行异步任务,返回一个 Future
对象,后者用于获取任务的执行结果。
在这个代码片段中,Callable<Integer> task = () -> { Thread.sleep(2000); return 42; };
使用了 Java 8 引入的 Lambda 表达式来创建一个 Callable
接口的实例。
具体解释如下:
Callable<Integer>
:指定了task
是一个返回整数类型结果的Callable
接口实例。->
:Lambda 操作符,用来分隔参数列表和 Lambda 表达式的主体部分。{}
:Lambda 表达式的主体,即方法体。Thread.sleep(2000)
:在任务执行的过程中暂停当前线程 2000 毫秒(即 2 秒)。return 42
:返回结果为整数 42。
因此,这个 Lambda 表达式实现了 Callable
接口的 call()
方法的具体逻辑:让当前线程休眠2秒,然后返回整数值 42。在实际执行时,这个任务会被提交给线程池执行,并且通过 Future
接口获取任务执行结果的返回值为 42。
Lambda 表达式简化了匿名内部类的书写方式,并且使代码更加简洁和易读。在这个例子中,Lambda 表达式代替了原先需要通过匿名内部类实现的 Callable
接口中的call()
方法。
在前面提到的代码片段中,实际上并没有直接调用 call()
方法。在这里,并没有显式地调用 task.call()
方法。相反,通过将 task
对象提交给一个线程池的 submit
方法,线程池会在后台执行这个 task
中的 call()
方法。
具体来说,线程池中的工作线程会从任务队列中取出 task
,然后调用 call()
方法,在 call()
方法中执行任务的具体逻辑。在这个例子中,任务的具体逻辑是让当前线程休眠2秒后返回整数值42。
因此,通过将 Callable
对象提交给线程池的 submit
方法,实际是启动了异步执行该任务的过程。线程池中的工作线程会执行 call()
方法的逻辑,并最终返回结果。
Future
接口:
Future
接口表示一个异步计算的结果,可用于判断任务是否完成、取消任务的执行、获取任务的结果等。Future
接口定义了以下方法:
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
接口的 get()
方法可以阻塞等待任务的执行结果,如果任务尚未完成则会阻塞当前线程,直到任务完成并返回结果。如果任务已经完成,get()
方法会立即返回。
下面是一个简单示例,演示如何使用 Callable
和 Future
来执行异步任务并获取任务的执行结果:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableFutureExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(1);
Callable<Integer> task = () -> {
Thread.sleep(2000);
//这里也可以执行代码块
return 42;
};
Future<Integer> future = executor.submit(task);
try {
Integer result = future.get();
System.out.println("Task result: " + result);
} catch (Exception e) {
e.printStackTrace();
}
executor.shutdown();
}
}
在这个示例中,我们创建了一个带有延迟的 Callable
任务,将其提交给一个线程池,并通过 Future
对象获取任务的执行结果。