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??

Steve Kuo
  • 61,876
  • 75
  • 195
  • 257
Eslam Hamdy
  • 7,126
  • 27
  • 105
  • 165

5 Answers5

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".

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 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? – Cratylus Sep 05 '12 at 20:08
  • @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`. – Jon Skeet Sep 05 '12 at 20:13
  • 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`. – Cratylus Sep 05 '12 at 20:19
  • 2
    @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. – Jon Skeet Sep 05 '12 at 20:28
  • So you are saying the approach I saw with custom threads like this *was* a bad design? – Cratylus Sep 05 '12 at 20:35
  • @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. – Jon Skeet Sep 05 '12 at 20:37
3

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

Erick Robertson
  • 32,125
  • 13
  • 69
  • 98
  • 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.) – Jon Skeet Sep 05 '12 at 16:30
  • Why does it matter how it *could* have been designed? – Erick Robertson Sep 05 '12 at 17:13
  • 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. – Jon Skeet Sep 05 '12 at 17:29
  • 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. – Jon Skeet Sep 05 '12 at 18:17
  • 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? – Erick Robertson Sep 06 '12 at 13:55
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");
  }
heretolearn
  • 6,387
  • 4
  • 30
  • 53
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();
}
Brian
  • 17,079
  • 6
  • 43
  • 66
-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");
  }
};
Cratylus
  • 52,998
  • 69
  • 209
  • 339
  • He was asking exactly what you asked. He wanted to know what exactly called his runnable's run method. – Brian Sep 05 '12 at 16:33
  • @Brian:I don't ask anything.OP asks why is `Cat` printed.I answered that.Because he ignores `Runnable` passed in. – Cratylus Sep 05 '12 at 16:37
  • 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. – Brian Sep 05 '12 at 16:40
  • You mean that there could be an implementation of `Thread(Runnable target)` that ignores the `target` when the thread is `run`? – Cratylus Sep 05 '12 at 16:45
  • @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 http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#run%28%29 – Cratylus Sep 05 '12 at 20:09