`Runnable`和`Callable`都是用于创建线程的接口,它们的区别如下:
1. 任务类型不同:
- `Runnable`接口用于创建只需要执行一次的任务,如启动一个线程、打印一条消息等。
- `Callable`接口用于创建需要多次执行的任务,如从数据库中查询数据、计算一些复杂的数学问题等。
2. 返回结果方式不同:
- `Runnable`接口没有返回值,因此需要在程序中手动获取执行结果,如使用`Future`类。
- `Callable`接口有返回值,可以通过调用`call()`方法获取执行结果,并且可以在任务执行过程中抛出异常。
3. 异常处理方式不同:
- `Runnable`接口不能在任务执行过程中抛出异常,只能在程序中手动捕获异常。
- `Callable`接口可以在任务执行过程中抛出异常,并且可以在任务执行结束后将异常作为返回值返回。
要使用`Callable`接口获取执行结果,可以使用`Future`类来获取任务的结果。具体步骤如下:
1. 创建`Callable`对象,并设置需要执行的任务和参数。
```java
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
// 执行需要返回结果的任务
return "result";
}
};
```
2. 创建`ExecutorService`对象,并使用`submit()`方法将`Callable`对象提交给线程池执行。
```java
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(callable);
```
3. 使用`Future`类的`get()`方法获取任务的结果。
```java
Future<String> future = executorService.submit(callable);
try {
String result = future.get(); // 等待任务完成并获取结果
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
```
需要注意的是,如果任务在执行过程中抛出了异常,则会在`get()`方法中抛出`ExecutionException`异常,需要在代码中手动捕获该异常。另外,如果任务执行时间较长,可能会阻塞主线程,建议使用异步执行的方式来避免这种情况。