35

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?

Boann
  • 48,794
  • 16
  • 117
  • 146
  • 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. – Stephen C Aug 19 '13 at 03:45

2 Answers2

28

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!)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Overriding run doesn't explain why it ever needed to be public though. – Boann Aug 19 '13 at 03:35
  • @Boann - but what is the harm? Besides, see the 2nd bullet point. That was certainly legitimate in the old days. – Stephen C Aug 19 '13 at 03:38
  • 2
    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. – Boann Aug 19 '13 at 03:45
  • 1
    @Boann ... 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. – Stephen C Aug 19 '13 at 03:50
  • 2
    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). – Boann Aug 19 '13 at 04:02
  • 1
    ++Actually, overriding a deprecated method seems to be a warning in Eclipse, though that's not such a bad thing. – Boann Aug 19 '13 at 04:16
  • 2
    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. – Stephen C Aug 19 '13 at 04:16
  • 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. – Gilbert Le Blanc Aug 19 '13 at 09:22
  • @StephenC Deprecation isn't just for positively harmful things. "A deprecated class or method is like that. It is no longer important" http://docs.oracle.com/javase/8/docs/technotes/guides/javadoc/deprecation/deprecation.html – Jimmy T. Sep 02 '16 at 19:22
  • @JimmyT. Some people might use Deprecated it like that. Oracle / Sun hasn't / doesn't. And for good reason. – Stephen C Sep 03 '16 at 00:26
  • @StephenC Things like java.awt.Component.enable() don't seem to be positively harmful to me. – Jimmy T. Sep 03 '16 at 06:27
  • 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. – Stephen C Sep 03 '16 at 06:46
  • @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. – nikel Feb 08 '17 at 11:14
  • @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. http://www.codejava.net/java-core/the-java-language/java-8-lambda-runnable-example – Stephen C Sep 26 '17 at 12:39
  • 1
    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. – Holger Sep 26 '17 at 13:25
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.

Community
  • 1
  • 1
eis
  • 51,991
  • 13
  • 150
  • 199
  • 3
    "there is reasons for it to implement some kind of interface like that" Uh, such as? – Boann Aug 19 '13 at 06:29
  • 1
    +1 especially for mentioning that interface methods must be public in Java. – Stephan B Aug 19 '13 at 06:30
  • @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* . . . – ruakh Aug 19 '13 at 06:31
  • 1
    @ruakh 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 :P – eis Aug 19 '13 at 06:37
  • @Boann "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". – eis Aug 19 '13 at 06:38
  • 3
    @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. – ruakh Aug 19 '13 at 06:57
  • @ruakh 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. – eis Aug 19 '13 at 07:33
  • 3
    @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. – ruakh Aug 19 '13 at 15:00
  • 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. – eis Aug 19 '13 at 16:37