Inspired by this SO question, I'd like to better understand the contract defined by Runnable
, along with when it is and is not acceptable to use the Runnable
interface. We know that Runnable
's most common use-case is to be implemented by a class that is intended to be executed on a separate thread:
Runnable task = () -> {
// Code to be executed on another thread
};
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(task);
This yields two questions:
- Is this the only acceptable pattern for its usage?
- If not, what are other acceptable usage patterns for
Runnable
that do not revolve around multithreading?
The use-case in the original SO question is to create a generic way to execute code before and after a method's execution without repetition, such as:
public void example1() {
before();
method1();
after();
}
public void example2() {
before();
method2();
after();
}
Eran's answer proposes using Runnable
to allow encapsulation of the logic for each method, along with a single method that accepts the Runnable
as an argument and invokes Runnable#run
at the appropriate time:
public void call(Runnable method){
before();
method.run();
after();
}
call( () -> { method1(); });
call( () -> { method2(); });
However, using Runnable
in this fashion was met with some disagreement, stating that this is not an acceptable use of Runnable
. Is this is a valid concern, or a matter of stylistic opinion?
From my own research, the Javadoc for Runnable
states the following contract, which seems to still be upheld with this usage of Runnable
:
The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread.
Further, if usage outside of the context of multithreading were discouraged or disallowed, I would expect either:
- The Javadoc to mention it somewhere, or
Runnable
to be in a concurrency-specific package, e.g.java.util.concurrent
, however it is available injava.util
.
Best Answer
While it is still clearly a matter for debate among the community, Alex revealed a comment left by Brian Goetz, Java Language Architect at Oracle, which I believe is the definitive canonical answer to this question. I've copied his comments below, emphasis mine: