7

I got this as an interview question.

why isn't Thread class final? Why would you extend a Thread ever?

I could not come up with real world use cases.

Cœur
  • 37,241
  • 25
  • 195
  • 267
user2434
  • 6,339
  • 18
  • 63
  • 87
  • 3
    Note: Note, since JDK 1.5, the recommended way is to use Executors, rather than Threads directly: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executor.html http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html So usually, you should not only not subclass Thread, you also shouldn't even create a Thread instance directly. – Puce May 02 '12 at 14:23

6 Answers6

10

From Oracle's documentation:

There are two ways to create a new thread of execution. One is to declare a class to be a subclass of Thread. This subclass should override the run method of class Thread. The other way to create a thread is to declare a class that implements the Runnable interface.

So the answer is "you may want to subclass Thread to override its run() method."

The quoted paragraphs have been in the Java documentation going back as far as JDK 1.1. Java has added other convenient classes for managing concurrency, most notably, the executors mentioned in the comments, possibly diminishing or eliminating the need to extend Thread. They cannot make it final, however, because that would break backward compatibility.

As far as practical reasons go, I think the only reason you may want to extend Thread rather than implement Runnable today would be to override its methods other than run(). For example, you may want to add logging or additional clean-up.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 5
    I have found that overriding interrupt() can also be useful if the Thread is executing IO (ie close a socket to interrupt reading/writing). – John Vint May 02 '12 at 14:20
2

This is pretty much just taken from John Vint's comment, but I think it's the best answer.

The only time I can think of where I might extend Thread rather than implementing Runnable -- or, even better, just using an ExecutorService with a Future -- is when I needed to override Thread.interrupt() to do some cleanup. Otherwise, I can't see any practical reason to actually extend Thread.

Tim Pote
  • 27,191
  • 6
  • 63
  • 65
1

Two cases:

  1. To create a new kind of Thread, perhaps one that cleans up some resource after finishing, etc
  2. To override the run() method, rather than providing a Runnable to the constructor (note: avoid this pattern - it's not the right approach)
Bohemian
  • 412,405
  • 93
  • 575
  • 722
1

Another reason that Thread is not final is that in the early days of Java, overriding run() was considered to be a good design pattern. (I guess, in the days before anonymous classes, it was thought to be "neater" to subclass Thread than to create a free-standing class that implements Runnable.)

Anyway, once Java 1.0 was released it because impossible to fix the problem by changing Thread to be final. That would have broken a lot of existing code.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

Let me put this in the following way: When designing a language, which is a tool like any other, one should think in terms of pros and cons and not just limit the tool because we aren't able to see applicable real use cases. By doing this we are able to understand such decisions theoretically. Basically, the exercise is asking the other way round.

Why Thread should be final?

Let me get to the point.


(I'm not including the backward compatibility argument, personally, I don't like it, as I think we should always be focused on improving locally)

To be able to discuss such subject we need to understand the benefits of declaring a class as final or not.

Performance

Here TofuBeer said:

Virtual (overridden) methods generally are implemented via some sort of table (vtable) that is ultimately a function pointer. Each method call has the overhead of having to go through that pointer. When classes are marked final then all of the methods cannot be overridden and the use of a table is not needed anymore - this it is faster.

Some VMs (like HotSpot) may do things more intelligently and know when methods are/are not overridden and generate faster code as appropriate.

Security

Here oracle highlights:

It is better to design APIs with security in mind. Trying to retrofit security into an existing API is more difficult and error prone. For example, making a class final prevents a malicious subclass from adding finalizers, cloning, and overriding random methods.

There is also issues with invariants and sensitive information. However, all security concerns are project specific and not applicable to a tool which can be used in non-security-concerned scenarios.

Convenience

andersoj referred here this nice IBM article:

final classes and methods can be a significant inconvenience when programming -- they limit your options for reusing existing code and extending the functionality of existing classes. While sometimes a class is made final for a good reason, such as to enforce immutability, the benefits of using final should outweigh the inconvenience. Performance enhancement is almost always a bad reason to compromise good object-oriented design principles, and when the performance enhancement is small or nonexistent, this is a bad trade-off indeed.

So, from my point of view, if there is no strong benefit to set the class as final, if JVM's are capable of doing such performance optimisations, I would say the convenient argument wins.

As so, we can extend the Thread class and do whatever we want with it, some initialization/finalization stuff, like logging, change the thread names, the type of thread... It up to you!

Community
  • 1
  • 1
João Melo
  • 726
  • 7
  • 8
0

It may be fields to hold the thread-local variables in the derived Thread class. Such variables can be accessible also when run() methods is not overridden and the thread executes Runnables as usual. Such custom threads may be managed by the standard ExecutorService, creating them in the custom ThreadFactory and discarding as required.

I am aware there is also ThreadLocal, but if the fields require cleanup (say they are the database connections), this can be rather elegantly done by calling super.run() to process Runnables and putting finalization immediately before the run method returns (so the thread terminates).

Audrius Meškauskas
  • 20,936
  • 12
  • 75
  • 93