java callable疑惑

本文详细探讨了Java并发包中的线程池如何使用Callable接口,并通过FutureTask实现,深入理解线程池原理及Callable与Runnable接口之间的转换过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java callable疑惑:
今天突然想起了在java concurrent 里面的线程池使用了callable这个接口,

看了 线程持的源码和Futuretask的源码终于明白了
FutureTask 里面哟个内部类:Sync 这个内部类中包含了
private volatile Thread runner; 这样的一个定义
和 private V result; 的定义 我就明白了
在使用callable的时候最后还是会使用runnable这个接口

void innerRun() {
if (!compareAndSetState(READY, RUNNING))
return;

runner = Thread.currentThread();//获取当前线程
if (getState() == RUNNING) { // recheck after setting thread
V result;
try {
result = callable.call();
} catch (Throwable ex) {
setException(ex);
return;
}
set(result);// 将得到的值赋值给 private V result; 这个变量
} else {
releaseShared(0); // cancel
}
}


在看看线程池的原理:
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
在 submit 中会实现一个RunnableFuture, 而Futuretask实现了RunnableFuture的接口!
### 如何在Java中提交Callable任务 为了理解如何在Java中提交`Callable`任务,重要的是认识到`Callable`接口是在JDK1.5版本之后被引入来弥补`Runnable`接口的一些局限性[^3]。具体来说,`Runnable`不提供任何返回值也不能处理异常,而这些功能对于某些应用场合是非常必要的。 当涉及到执行异步计算并获取其结果时,可以利用实现了`Callable<V>`接口的对象,其中V表示该任务完成后的返回类型。与仅能通过实现`void run()`方法定义操作逻辑的`Runnable`不同,`Callable`允许开发者指定一个带有泛型参数的方法——`V call() throws Exception;`,这使得它能够抛出受检异常以及返回执行的结果[^4]。 要在一个程序里实际地提交这样的任务给线程池去运行,则需要用到`ExecutorService`所提供的API之一:`<T> Future<T> submit(Callable<T> task)` 方法。下面是一个简单的例子展示怎样创建和提交一个`Callable`类型的作业: ```java import java.util.concurrent.*; public class CallableExample { public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); // 创建一个实现了Callable接口的任务实例 Callable<Integer> task = () -> { Thread.sleep(2000); // Simulate a long-running job. System.out.println("Task completed."); return 123; }; try { // 提交任务到线程池,并立即获得一个Future对象作为凭证 Future<Integer> future = executor.submit(task); // 主线程继续做其他事情... // 当准备好接收子线程运算结果的时候调用get() Integer result = future.get(); // This will block until the computation is done. System.out.printf("The result of the submitted Callable task was: %d%n", result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } finally { executor.shutdown(); } } } ``` 在这个案例中,首先创建了一个单一线程的`ExecutorService`实例用于管理我们的后台工作线程。接着构建了一个匿名内部类形式的具体化`Callable<Integer>`对象,在它的`call()`方法体内模拟了一些耗时较长的操作,并最终返回整数值123作为此次任务的成功响应数据。最后一步就是把上述准备好的可调用单元传递给`submit()`函数来进行调度安排;与此同时会立刻得到一张代表未来可能存在的输出物的契约书——即`Future<?>`实体。一旦想要取回那个预期中的答案就可以随时访问此代理上的相应属性或行为(比如这里用了阻塞式的`future.get()`等待直到有确切消息传来为止),当然在此之前还可以安全地让主线程去做别的事而不必一直挂起等待。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值