Both have their uses, and both are supported by the Executor framework in java.util.concurrent. Runnable has been around longer, but it is still in use and not discouraged.
Callables can throw exceptions and return values, which makes them the better abstraction for result-bearing tasks (such as fetching a resource from the network, performing an expensive computation of a value, and the like) [from Java Concurrency in Practice by Goetz, Bloch et. al., the standard work on Java concurrency].
So, if you are designing an API, I would suggest using Callables when possible. If you are sure that the tasks will not return values and will not throw exceptions, then Runnables are also a valid choice. There is no black and white here, especially because Runnables can easily be wrapped in Callables and vice versa.
As an aside, note that your Callable implementation need not declare throws Exception
; the fact that Callable itself declares it is only to allow implementors to throw any checked exceptions. Callers of your Callable who rely solely on the Callable interface will have to write exception handling code, though.
Also note that Callables need not return a value; you can simply declare your Callable to return Void
(with capital 'V
').
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…