Why does Thread implement Runnable?
Asked Answered
H

3

39

A Java Thread's run() method is called by the JVM, on that thread, when the thread starts. To give a thread something to do, you can make a subclass of Thread and override its run() method, or (preferred) you can supply a Runnable to the thread's constructor. That's fine.

I was in the midst of making a subclass of Thread and overriding run, and I realized I couldn't make the method protected as I expected to because Thread.run() is public. Then I realized why: it has to be public because Thread implements Runnable. But why does it implement Runnable?

It doesn't seem logical. A thread is startable (from the current thread), but you don't run it in the same way you run() a Runnable (from the current thread); the thread runs itself (on its own thread). If you do call a Thread's run method manually, then you're not using it as a Thread, just a heavyweight Runnable.

Because of the design, any code with access to a Thread object can call its public run method and potentially poke into code that is not intended to be public or designed to be called that way. It also allows very peculiar things like this:

Thread.currentThread.run();

Is there a legitimate use for Thread implementing Runnable that I'm not seeing?

Housley answered 19/8, 2013 at 3:21 Comment(1)
@cHao - If you understood the history, and the goals of Java (in particular the goal of running code that is many decades old), you would realize that they are doing the best that is humanly possible, under the circumstances.Lakeshialakey
L
31

The reason is "backwards compatibility".

The Thread class originated in Java 1.0 ... or earlier. In those days, Java didn't have inner classes, and so there wasn't a light-weight way to implement a Runnable instance. If you look at old threading examples and tutorials from that era, it is common to see classes that extend Thread and override the run() method.

Over time, it was realized that extending Thread is not a good idea (for various reasons). However, the Thread design could not be changed because that would have made old Java code incompatible with newer JVMs.


Is there a legitimate use for Thread implementing Runnable that I'm not seeing?

It depends what you mean by "legitimate".

  • Old code that was written in the early days is not "illegitimate" by virtue of doing things the old way. There is nothing "broken" about it.

  • There are potentially scenarios where it does make sense to extend Thread and override the run() method. For example, you might want run() to implement some special mechanism for passing info in or out of the supplied Runnable, or implement some special exception handling, or ... make the thread "restartable".

  • There might even be scenarios where you'd want to call run() directly on a thread object. For instance if you were handed some "dogs breakfast" code that extended Thread and you had to convert it to run in a thread pool without modifying the original code. You might consider instantiating the crufty thread class and passing the instances as runnables to the threadpool to run. (Yes ... horrible!)

Lakeshialakey answered 19/8, 2013 at 3:30 Comment(15)
Overriding run doesn't explain why it ever needed to be public though.Housley
@Housley - but what is the harm? Besides, see the 2nd bullet point. That was certainly legitimate in the old days.Lakeshialakey
The harm is that regardless of whether one subclasses Thread, or subclasses Runnable and gives it to the Thread's constructor, it's not possible to prevent the code from being publicly callable via Thread.run. Plus it's confusing that there are both public run() and start() methods on Thread, and calling the wrong one could still seem to work. Also, although I came to Java after inner classes were added, I don't see how the lack of them makes it easier to make a subclass of Thread than a subclass of Runnable.Housley
@Housley ... frankly, it doesn't. But your whole argument seems to be based on the assumption that these things were understood in the early 1990's. They weren't. And that is why the API is like it is. Criticisms of Java based on the 20+ years of hind-sight are, irrelevant ... unless you are intending to implement a new language. And frankly, THIS example is little more than a cosmetic issue. It does not stop people from writing good maintainable code.Lakeshialakey
Well it hadn't occurred to me the decision was so old. So would you agree it's never truly been legitimate or useful; it's just a historical slip? If that's true then Thread.run() should be marked @Deprecated (which will not have any effect on overriding it, but it will at least dissuade people from misusing it by directly calling it instead of start(), or passing Threads around as if they were common Runnables).Housley
++Actually, overriding a deprecated method seems to be a warning in Eclipse, though that's not such a bad thing.Housley
No it should not be deprecated. Deprecation is for things that are positively harmful. Besides, it is not technically possible to deprecate a method defined in a interface without deprecating it in all places where the interface is used. The right way to deal with people mistakenly calling run() instead of start() is to use a tool like PMD or Findbugs.Lakeshialakey
I write lots of Runnables in my Java applications. Some I execute directly, and others I use in a Thread. I start every Swing application with a Runnable that instantiates the model and instantiates the JFrame.Puppet
@StephenC Deprecation isn't just for positively harmful things. "A deprecated class or method is like that. It is no longer important" docs.oracle.com/javase/8/docs/technotes/guides/javadoc/…Julianejuliann
@JimmyT. Some people might use Deprecated it like that. Oracle / Sun hasn't / doesn't. And for good reason.Lakeshialakey
@StephenC Things like java.awt.Component.enable() don't seem to be positively harmful to me.Julianejuliann
They are harmful to code style. Yes ... there are exceptions. But note that those methods were deprecated >very< early; i.e. Java 1.1 ... before there was a significant amount of Java code in production. If Oracle deprecated those methods now for the reason that they were deprecated, there would be howls of protest from Java customers with support contracts.Lakeshialakey
@StephenC : Could you please explain : "In those days, Java didn't have inner classes, and so there wasn't a light-weight way to implement a Runnable instance. " The way i think, simply extending the thread class or implementing the Runnable interface in a new class ,; is kind of the same in terms of complexity.Ablaut
@naker. The light-weight option is to use an anonymous inner class to implement the Runnable. That was not available until Java 1.1. And now with Java 8 you could even use lambda expressions; e.g. codejava.net/java-core/the-java-language/…Lakeshialakey
Well, I consider calling Thread.run() wrong enough to deserve to get deprecated, but unfortunately, overriding Thread.run() is still the correct thing for subclasses and you can’t deprecate only one of these two usages.Doukhobor
K
4

Overriding run doesn't explain why it ever needed to be public though.

If this is your issue, I think there's simple answer for that: methods implementing an interface must always be public in java. It would be possible with an abstract class for it to be protected, but if Thread were abstract, you wouldn't be able to use it as such.

As to why is Thread implementing Runnable in the first place, java must have a way of knowing at which part the thread is actually doing its job. They use run method for that. They could have more clearly separated the logic of just implementing Runnable and having Thread subclass implement that, but that is what I consider a minor mistake which is hard to change due to historical reasons.

TLDR; AFAIK there really isn't a good reason for a Thread to implement Runnable, but there is reasons for it to implement some kind of interface like that - they should've just probably had some kind of separated interface like ThreadRunnable instead of using the same Runnable interface that has other uses as well.

Note also that on modern java you should probably anyway use Callables and FutureTasks instead of Threads. "The integration of timeouts, proper cancelling and the thread pooling of the modern concurrency support are all much more useful to me than piles of raw Threads.", quoting another answer here on stackoverflow.

Kirkwood answered 19/8, 2013 at 6:9 Comment(9)
"there is reasons for it to implement some kind of interface like that" Uh, such as?Housley
+1 especially for mentioning that interface methods must be public in Java.Imtiaz
@Stephan: Why would you upvote an answer for giving information that's already in the question? To me, that seems more like a reason to downvote . . .Baroness
@Baroness I don't see that mentioned explicitly in the question, at least not in the way that it would deserve a downvote, but maybe that's just me :PKirkwood
@Housley "java must have a way of knowing at which part the thread is actually doing its job. They use run method for that." this is the reason I'm referring to - they need some kind of placeholder that's telling the implementer "this is the place where you should put the workload on".Kirkwood
@eis: That's a non sequitur. Just because there's a placeholder method that subclasses can/should override, that doesn't mean that said placeholder method should be public, or declared in an interface. On the contrary: internal hooks usually aren't public.Baroness
@Baroness agreed. The way to implement that properly is that the method should be abstract & protected in the parent class. However, it seems that Thread class was wanted to be usable in itself, which an abstract class (a class containing an abstract method) wouldn't be. Doing these kind of things through interfaces seems to be the alternative then.Kirkwood
@eis: Not at all. You can have a non-abstract protected method. Again -- non sequitur. There's no connection between the different things you're saying.Baroness
Um. I know you can have a non-abstract protected method. What I said that you cannot have an abstract method without having an abstract class, and that an abstract class wouldn't be useful by itself.Kirkwood
C
-2

I think the answer for these question is:"when we define a thread by extending Thread class,we can't extend any other class. Hence, we are missing inheritance. But if we define a thread by implementing runnable interface ,we can extend any other class also. Hence we won't miss any inheritance benefit."

Congener answered 23/7, 2024 at 12:35 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Camphor
I think what happened is you misread this question as something like https://mcmap.net/q/15338/-quot-implements-runnable-quot-vs-quot-extends-thread-quot-in-java/217324, because the answer here isnt relevant to this question but is applicable to that one. Now, that other question has enough answers, it doesnt need any more. But the answer here does not explain why the Thread class was made to implement Runnable, see Stephen C's answer for something that does address this question.Garcia

© 2022 - 2025 — McMap. All rights reserved.