Java Runnable 和 Callable 区别
在日常写代码的时候,尤其是做一些后台任务或者需要返回结果的线程操作,经常会碰到两种写法:一种是用Runnable,另一种是Callable。很多新手刚接触的时候,总觉得它们长得差不多,分不清什么时候该用哪个。
其实你可以把它们想象成两种“任务说明书”——它们都是给线程干的活,但要求和结果完全不一样。

---
先看Runnable:只管干活,不管回报
Runnable就像你去餐馆点一碗面,给老板的要求就是“煮一碗面”,老板做好端上来,你不用管他是怎么煮的,也不用问他要额外的反馈。用代码来说,Runnable的run()方法没有返回值,只能通过它去做一些不需要结果的事情,比如打印日志、更新界面上的进度条,或者只是执行一个简单的计算但不需要保存结果。
举个生活化的例子:你早上出门前,让家人“把客厅的窗户打开通风”。家人照做就好,你不会问“你打开窗户之后看到了什么”,也不会要他把看到的东西汇报给你。Runnable就是这种“只管执行,不拿结果”的任务。
但如果哪天你出门前说“把客厅窗户打开,顺便帮我看看外面今天会不会下雨,回来告诉我”,这时候就需要另一种任务了。
---
再看Callable:干活,还要带结果
Callable就像你给家人的要求里多了“带结果回来”。它的call()方法有返回值,还可以抛出异常,适合那些需要拿到执行结果的场景,比如你要统计一批数据的总和、或者调用第三方接口获取一个结果再处理。
还是用刚才的例子:你让家人开窗,还要带回来“外面有没有下雨”的答案。这时候家人不仅要执行开窗的动作,还要给你一个明确的回答——“有雨”或者“没雨”。Callable就是这种“做完活,还要给你一个结果”的任务。
从代码的角度说,Runnable的run()方法是void类型,写起来很简单,但拿不到返回值;而Callable的call()方法有泛型返回值,你可以指定要拿到什么类型的结果,比如整数、字符串甚至对象。
---
实际用的时候怎么选?
其实核心的区别就看你需不需要返回值:
- 如果你只是要让线程做一件事,不需要知道它做得怎么样,也不用拿结果,那就用
Runnable。比如启动一个线程去下载一个图片,只要它能完成下载就行,不需要返回下载的速度或者文件大小。 - 如果你需要线程执行完后给你一个结果,或者执行过程中可能出错需要处理异常,那就选
Callable。比如同时去查两个接口,等它们都返回结果后再合并处理,这时候Callable就能帮你把结果拿回来。
举个更贴近代码的例子:你有一个计算1到100之和的任务。用Runnable的话,你只能自己在run()里打印结果,别的地方拿不到;用Callable的话,你可以让线程把这个和作为返回值,再存到一个变量里给后面的代码用。
最后要提一句,很多人容易搞混的是,Runnable和Callable本身都不是线程,它们只是线程要执行的“任务”。要让它们跑起来,还得把它们交给Thread或者ExecutorService之类的线程工具,但这是另外的知识点了,不用现在纠结。
简单总结一下:一个无返回值,一个有返回值;一个只能执行,一个既能执行又能拿结果。搞懂这个,再用的时候就不会选错了。