Runnable 无返回值且不能抛出受检查异常,适用于无需结果的后台任务;Callable 可返回结果并抛出异常,需结合 Future 获取结果和处理异常,适用于需要反馈的场景。

Runnable
Callable
Runnable
Callable
Runnable
Callable
理解
Runnable
Callable
Runnable
run()
public interface Runnable {
public abstract void run();
}这个
run()
run()
run()
throws Exception
IOException
run()
RuntimeException
Callable
call()
public interface Callable<V> {
V call() throws Exception;
}call()
call()
V
call()
Exception
ExecutorService
Future
在我看来,
Runnable
Callable
实际使用中,
Runnable
Thread
ExecutorService
Callable
ExecutorService
submit()
Future
Callable
Runnable
这个问题我经常被问到,也常常思考。在我看来,Java 引入
Callable
Runnable
Runnable
Runnable
Runnable
Runnable
run()
volatile
synchronized
run()
FileNotFoundException
SQLException
run()
try-catch
RuntimeException
Callable
ExecutorService
Future
Callable
Runnable
Runnable
Runnable
Callable
选择
Runnable
Callable
关注点是“执行”而非“结果”时,选择 Runnable
Runnable
需要获取任务的计算结果,或者需要处理任务抛出的特定异常时,选择 Callable
Callable
Future
一个经验法则:
Runnable
Callable
我发现很多新手会倾向于无脑使用
Callable
Runnable
ExecutorService.submit()
Runnable
Future<?>
Future
Future
Callable
Future
Callable
Callable
Callable
ExecutorService
ExecutorService
Future
Future
具体来说,
Future
isDone()
isCancelled()
cancel(boolean mayInterruptIfRunning)
get()
Future
Callable
get()
ExecutionException
getCause()
get(long timeout, TimeUnit unit)
TimeoutException
在我看来,
Future
下面是一个简单的代码示例,展示了如何使用
Callable
Future
import java.util.concurrent.*;
// 1. 定义一个实现 Callable 接口的任务
class SummingTask implements Callable<Integer> {
private final int start;
private final int end;
public SummingTask(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + " 开始计算 " + start + " 到 " + end 的和...");
int sum = 0;
for (int i = start; i <= end; i++) {
sum += i;
// 模拟耗时操作,或者引入一个随机的异常
if (i == start + 5 && Math.random() < 0.2) { // 大约20%的几率抛出异常
throw new IllegalStateException("模拟计算过程中发生了一个错误,例如数据不一致。");
}
Thread.sleep(10); // 每次加法后暂停一小会儿
}
System.out.println(Thread.currentThread().getName() + " 计算完成,结果: " + sum);
return sum;
}
}
public class CallableFutureExample {
public static void main(String[] args) {
// 2. 创建一个 ExecutorService 来管理和执行任务
// 这里使用固定大小的线程池,实际项目中可以根据需求选择不同类型的线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
// 3. 创建 Callable 任务实例
Callable<Integer> task1 = new SummingTask(1, 10);
Callable<Integer> task2 = new SummingTask(11, 20);
Callable<Integer> task3 = new SummingTask(21, 30); // 增加一个可能抛出异常的任务
// 4. 提交 Callable 任务到 ExecutorService,并获取 Future 对象
Future<Integer> future1 = executor.submit(task1);
Future<Integer> future2 = executor.submit(task2);
Future<Integer> future3 = executor.submit(task3); // 提交可能失败的任务
System.out.println("所有任务已提交,主线程继续执行其他操作...");
try {
// 5. 通过 Future 对象获取任务结果,get() 方法会阻塞直到任务完成
System.out.println("尝试获取 task1 的结果...");
Integer result1 = future1.get(); // 可能会阻塞
System.out.println("Task 1 的结果是: " + result1);
System.out.println("尝试获取 task2 的结果...");
Integer result2 = future2.get(5, TimeUnit.SECONDS); // 最多等待5秒
System.out.println("Task 2 的结果是: " + result2);
System.out.println("尝试获取 task3 的结果...");
// 如果 task3 抛出了异常,get() 会抛出 ExecutionException
Integer result3 = future3.get();
System.out.println("Task 3 的结果是: " + result3);
} catch (InterruptedException e) {
// 当前线程在等待结果时被中断
Thread.currentThread().interrupt(); // 重新设置中断标志
System.err.println("主线程在等待结果时被中断: " + e.getMessage());
} catch (ExecutionException e) {
// Callable 任务内部抛出的异常会被封装在 ExecutionException 中
System.err.println("任务执行失败: " + e.getCause().getMessage());
e.getCause().printStackTrace(); // 打印原始异常堆栈
} catch (TimeoutException e) {
// get(timeout, unit) 方法超时
System.err.println("获取任务结果超时: " + e.getMessage());
// 此时可以选择取消任务
future2.cancel(true);
} finally {
// 6. 关闭 ExecutorService
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow(); // 强制关闭
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
System.out.println("ExecutorService 已关闭。");
}
}
}在这个例子中,
SummingTask
Callable
ExecutorService
Future
future.get()
Callable
IllegalStateException
ExecutionException
以上就是Runnable 和 Callable 接口有什么区别?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号