The only good reason to derive a subclass from
Thread is to extend its behavior - just like any other class. It's usually a better idea to implement
Runnable.
Delegation, when it satisfies the requirements, is a more flexible solution than specialization. While it's true that overriding run() is in some sense extending Thread's behavior, it's more in keeping with good OO practice to derive a Thread subclass only if you need to modify some more basic aspect. In the simple example programs you see in most books (where the author often just makes the main class a subclass of Thread), the two approaches are equivalent. In larger programs, this kind of failure to make the code reflect the design abstractions often leads to trouble.
Since the release of JDK 5, it's often a good idea to avoid using Thread at all (or avoid it as much as possible) because you may well prefer to use an
Executor instead. This can give you easy access to thread pools, for example. By implementing
Runnable rather than extending Thread, you minimize the amount of code that you might have to change later if you decide to use an Executor.
(Based on an answer by Jerry Pulley in
this thread)
In
Java 5, several other features have been introduced in this area. Aside from the
Executor, the
Callable interface is similar to
Runnable, but allows the thread to return a result.
Future handles returning a result, and also provides a way to cancel a running task.
JavaDoc:java.lang.RunnableJavaDoc:java.lang.ThreadJavaDoc:java.util.concurrent.CallableJavaDoc:java.util.concurrent.ExecutorJavaDoc:java.util.concurrent.Future
ThreadsAndSynchronizationFaq