Java 中的 Callable
接口是一个泛型接口,它定义了一个可以返回值或抛出异常的操作。Callable
接口通常用于需要返回结果的多线程场景。
下面是 Callable
接口的基本用法:
-
定义接口对象:
-
Callable<String> callable = () -> "hello, world";
这个示例代码定义了一个
Callable
接口对象,它不接受任何参数,并返回一个字符串类型的结果,这个结果是"hello, world"
。 -
使用接口对象:
FutureTask futureTask = new FutureTask(callable); new Thread(futureTask).start(); String res = (String) futureTask.get();//结果可能需要等待,会阻塞 System.out.println(res);
ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<String> future = executorService.submit(callable); String result = future.get(); System.out.println(result);
在这个示例代码中,我们通过调用
submit()
方法来将一个Callable
接口对象交给线程池执行,并获取一个Future
对象作为结果的占位符。然后,我们通过调用get()
方法来阻塞当前线程并获得最终的结果。输出结果为"hello, world"
。
Callable
接口需要在 call()
方法中实现具体的业务逻辑,并通过 return
语句返回结果,例如:
Callable<Integer> callable = () -> {
int sum = 0;
for(int i = 1; i <= 100; i++) {
sum += i;
}
return sum;
};
这个示例代码定义了一个 Callable
接口对象,它不接受任何参数,并返回一个整数类型的结果,这个结果是从 1 加到 100 的和。
Callable
接口还可以抛出异常,例如:
Callable<String> callable = () -> {
if(Math.random() > 0.5) {
return "hello, world";
} else {
throw new Exception("error");
}
};
这个示例代码定义了一个 Callable
接口对象,它可能返回一个字符串类型的结果或者抛出一个异常,这个异常包含一个错误信息 "error"
。
使用 Callable
接口时,通常需要使用线程池来管理多个线程的生命周期,以避免频繁地创建和销毁线程。一般来说,我们可以通过 ExecutorService
接口来创建一个线程池,并通过 submit()
方法将任务交给线程池执行。例如:
ExecutorService executorService = Executors.newFixedThreadPool(10);
List<Callable<String>> tasks = new ArrayList<>();
for(int i = 0; i < 10; i++) {
Callable<String> callable = () -> "task " + i;
tasks.add(callable);
}
List<Future<String>> results = executorService.invokeAll(tasks);
for(Future<String> future : results) {
System.out.println(future.get());
}
executorService.shutdown();
这个示例代码使用一个固定大小的线程池来执行 10 个任务,并将每个任务的执行结果保存到一个 Future
对象中。最后,我们通过遍历所有 Future
对象并调用 get()
方法来阻塞当前线程并获取最终结果。输出结果为:
task 0
task 1
task 2
task 3
task 4
task 5
task 6
task 7
task 8
task 9
总之,Callable
接口是 Java 中非常实用的一个接口,在需要返回结果或抛出异常的多线程场景下特别有用。它通常需要和 ExecutorService
接口一起使用,方便地管理多个线程的生命周期。