Thread object constructed by runnable overrides the run method
Asked Answered
C

5

5

Given this sample code:

Runnable r = new Runnable() {
  public void run() {
    System.out.print("Cat");
  }
};
Thread t = new Thread(r) {
  public void run() {
    System.out.print("Dog");
  }
};
t.start();

why is the output Dog and not Cat??

Claussen answered 5/9, 2012 at 16:23 Comment(1)
(Note in the Thread you can do @Override public void run() { super.run(); System.out.print("Dog"); }, and you'll get both.)Wetnurse
W
7

The implementation of run in Thread simply calls the Runnable provided in the constructor, if there is one. You're overriding that code, so if the new thread simply has its run method called regardless, the Runnable is ignored. Of course, you should be able to look at the source code to check that... (I've just done so, and while I'm not going to post the source here, it does exactly what I've described.)

What you've really exposed is an encapsulation problem - Thread shouldn't have these different, potentially conflicting, ways of saying what the thread should do. Basically, you should almost never extend Thread directly. Just because it's been designed badly doesn't mean you have to abuse that poor design ;)

EDIT: This is actually documented, in a somewhat roundabout way. start() is documented as:

Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.

And run() is documented as:

If this thread was constructed using a separate Runnable run object, then that Runnable object's run method is called; otherwise, this method does nothing and returns.

So the run() method is called as per start(), but you've overridden run(), which is the only method which will call the Runnable provided in the constructor.

Note that if you'd overridden the method like this:

Thread t = new Thread(r) {
  public void run() {
    super.run();
    System.out.print("Dog");
  }
};

Then the output would be "CatDog".

Wondawonder answered 5/9, 2012 at 16:27 Comment(6)
I don't follow why it is a bad design.Either one extends Thread or passes a Runnable as the task that the Thread must run.This is what the documentation specifies.If this can be misused as per the OP trick question, why is this a bad design?Mcmann
@Cratylus: Well for a start, because it doesn't prohibit you abusing it. But more importantly, it doesn't separate the concerns of "starting a new thread to run something" and "what to run". It would have been better (IMO) if Thread has been a final class and had forced you to pass in a Runnable.Wondawonder
I see what you mean.I think you are right, but I have seen code base extending Thread and creating custom threads, setting daemon as needed and ThreadGroup etc prior to concurrent package.This seems to be useful (back then) and this would not be possible though if the Thread was made as final.Mcmann
@Cratylus: Why would it not be possible? Which of those tasks requires you to extend Thread rather than just creating an instance and setting properties? Subclassing should be about changing behaviour, not just setting values.Wondawonder
So you are saying the approach I saw with custom threads like this was a bad design?Mcmann
@Cratylus: If it was extending Thread just to set some properties, then yes. There's nothing thread-specific there - it's an abuse of inheritance, IMO.Wondawonder
T
3

You have overridden Thread.run so that it doesn't execute the runnable. Instead it just prints "Dog".

Triclinium answered 5/9, 2012 at 16:26 Comment(5)
It doesn't have to work that way though. The implementation could be "If a target Runnable has been given, call that - otherwise, call the run method." (Actually, start() is documented to call run, but the whole class could have been designed differently.)Wondawonder
Why does it matter how it could have been designed?Triclinium
Because you didn't post anything to suggest that it's actually documented to run that way. Did you check before you're posting? It could have been implementation-specific, very easily.Wondawonder
Then you should be explaining that. And note that knowing that one implementation works that way isn't the same thing as knowing whether it's documented behaviour.Wondawonder
Since this check is made in the Java source code to Thread.run(), which is not a native method, how could this vary by implementation?Triclinium
P
0

It is because the function run() is overridden. And t call this function:

public void run() {
System.out.print("Dog");
}

You will get the o/p as cat when you execute r.start() Which will call the function

 public void run() {
    System.out.print("Cat");
  }
Piloting answered 5/9, 2012 at 16:27 Comment(2)
No, run() is not overloaded. It's overridden, which is different... and the rest of your answer doesn't really provide much enlightenment.Wondawonder
yes its overriding . sorry for the mistake. Have already changed it.Piloting
L
0

Taking a look at the source code for java.lang.Thread:

public void run() {
    if (target != null) {
        target.run();
    }
}

target is the Runnable field in the Thread that the Thread(Runnable) constructor uses to assign your r variable. When you override the run method in the Thread, you're changing the behavior of run to call

System.out.print("Dog");

instead of calling

if (target != null) {
    target.run();
}
Landwaiter answered 5/9, 2012 at 16:30 Comment(0)
M
-1

This is an anonymous class and you are redefining/overriding run. Are you using the passed-in Runnable inside your run? No you don't. So the question is, why did you expect it to print Cat?

 new Thread(r) {
  public void run() {
    System.out.print("Dog");
  }
};
Mcmann answered 5/9, 2012 at 16:31 Comment(5)
He was asking exactly what you asked. He wanted to know what exactly called his runnable's run method.Landwaiter
@Brian:I don't ask anything.OP asks why is Cat printed.I answered that.Because he ignores Runnable passed in.Mcmann
But the implementation of Thread doesn't necessarily have to work that way, a better answer would have been reminding him that Thread.run calls his runnable's run method, and that overriding it removed that behavior.Landwaiter
You mean that there could be an implementation of Thread(Runnable target) that ignores the target when the thread is run?Mcmann
@Brian:If this thread was constructed using a separate Runnable run object, then that Runnable object's run method is called; otherwise, this method does nothing and returns..So this is how it is specified.It is not implementation detail.Taken from docs.oracle.com/javase/7/docs/api/java/lang/…Mcmann

© 2022 - 2024 — McMap. All rights reserved.