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.

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.