Java Forum / First Aid / March 2004
Not understandable Thread behaviour
lonelyplanet999 - 05 Mar 2004 11:55 GMT Hi,
I found that if I do not include public void main() method in class extending Thread class, nothing can be output by it's run() method even if .start() being called on that Thread instance. Why will that happen ?
For example, for below program, nothing will be output as the program being run. If I un-comment those lines, I could only see text output by ot3, ot4 instances. Why ot1 & ot2 cannot print text out to console ?
public class OverloadThread { public static void main(String[] args) { Thread ot1 = new Thread(), ot2 = new Thread(); // ORunnable or1 = new ORunnable(), or2 = new ORunnable(); // Thread ot3 = new Thread(or1), ot4 = new Thread(or2); ot1.setName("ot1"); ot2.setName("ot2"); // ot3.setName("ot3"); // ot4.setName("ot4"); ot1.start(); ot2.start(); // ot3.start(); // ot4.start(); } }
class Othread extends Thread { public void run() { for (int i=0; i<5; i++) { System.out.println("OThread."+Thread.currentThread().getName()+".run()"); this.run("Overload"); } } public void run(String s) { System.out.println("OThread."+Thread.currentThread().getName()+".run(String)"); } }
//class ORunnable implements Runnable { // public void run() { // for (int i=0; i<5; i++) { // System.out.println("ORunnable."+Thread.currentThread().getName()+".run()"); // this.run("Overload"); // } // } // public void run(String s) { // System.out.println("ORunnable."+Thread.currentThread().getName()+".run(String)"); // } //}
Why Thread instance class (or it's subclass) can only output text to console when it also includes public void main() method in it's class definition ?
class MyThread extends Thread {
public static void main(String[] args) { MyThread t = new MyThread(); t.start(); }
public void run() { System.out.println("Thread"); }
}
Running this program produce below output
Thread
:) Ryan Stewart - 05 Mar 2004 12:41 GMT > Hi, > > I found that if I do not include public void main() method in class > extending Thread class, nothing can be output by it's run() method > even if .start() being called on that Thread instance. Why will that > happen ? It won't. Your findings are incorrect. There is something else wrong.
> For example, for below program, nothing will be output as the program > being run. If I un-comment those lines, I could only see text output > by ot3, ot4 instances. Why ot1 & ot2 cannot print text out to console > ? Because below, ot1 and ot2 are instances of java.lang.Thread. Thread's run method does nothing. I think you meant to make them Othread's.
> public class OverloadThread { > public static void main(String[] args) { [quoted text clipped - 15 lines] > public void run() { > for (int i=0; i<5; i++) { System.out.println("OThread."+Thread.currentThread().getName()+".run()");
> this.run("Overload"); > } > } > public void run(String s) { System.out.println("OThread."+Thread.currentThread().getName()+".run(String) ");
> } > } [quoted text clipped - 3 lines] > // for (int i=0; i<5; i++) { > // System.out.println("ORunnable."+Thread.currentThread().getName()+".run()");
> // this.run("Overload"); > // } > // } > // public void run(String s) { > // System.out.println("ORunnable."+Thread.currentThread().getName()+".run(Strin g)");
> // } > //} > > Why Thread instance class (or it's subclass) can only output text to > console when it also includes public void main() method in it's class > definition ? Again, this is not a limitation of a Thread.
> class MyThread extends Thread { > [quoted text clipped - 14 lines] > > :) So does the following:
public class Foo { public static void main(String[] args) { MyThread t = new MyThread(); t.start(); } }
class MyThread extends Thread { public void run() { System.out.println("Thread"); } }
Jon A. Cruz - 05 Mar 2004 16:29 GMT > Hi, > > I found that if I do not include public void main() method in class > extending Thread class, In general, it's not a good idea to extend Thread. Just implement Runnable instead.
Ryan Stewart - 05 Mar 2004 18:01 GMT > > Hi, > > [quoted text clipped - 3 lines] > In general, it's not a good idea to extend Thread. Just implement > Runnable instead. Why is that anyhow? If you have a simple task for the thread to run, why add the extra step? Using Runnable feels clumsy, especially in naming the variables. Say I want to use a thread to write from a message queue to a log file or something along those lines:
MyLogger logger = new MyLogger(); // MyLogger implements Runnable Thread loggerThread = new Thread(logger); loggerThread.start();
Conceptually, what is "logger" and what is "loggerThread"? Why are they two different things? Extending Thread seems much cleaner, so what's the reason for not?
Eric Sosman - 05 Mar 2004 19:35 GMT > > > Hi, > > > [quoted text clipped - 16 lines] > different things? Extending Thread seems much cleaner, so what's the reason > for not? Take a look at the implementation of MyLogger. You didn't show it, but my crystal ball tells me that MyLogger is a subclass of Logger, that is, it specializes or extends the more general or less powerful superclass. Since a Java class can have only one superclass, MyLogger cannot extend both Logger and Thread. So, how can you run a MyLogger in a separate thread? Java's answer:
class MyLogger extends Logger implements Runnable
Now all is good. The relationship between MyLogger and Logger is just as it would be if no threads were involved: a MyLogger object "is a" Logger object, methods and fields are inherited as per usual, and so on. But at the same time, it's simple to run a MyLogger instance in a separate thread, using exactly the code you've shown.
If there were no Runnable interface and extending Thread were the only way to get parallel execution, it would still be possible to do this sort of thing but in a clumsier fashion:
class MyLogger extends Logger { ... }
class MyParallelLogger extends Thread { private final MyLogger logger; MyParallelLogger(MyLogger logger) { this.logger = logger; } public void run() { ... } }
MyParallelLogger mpl = new MyParallelLogger(new MyLogger()); mpl.start();
Implementing Runnable is easier than jumping through this silly hoop, I think.
 Signature Eric.Sosman@sun.com
Ryan Stewart - 07 Mar 2004 14:02 GMT > > > > Hi, > > > > [quoted text clipped - 53 lines] > Implementing Runnable is easier than jumping through this > silly hoop, I think. MyLogger is actually its own little thing, not extending anything, but I see your point. I hadn't considered the inheritance issue before. Thanks for the reply.
Steve Horsley - 05 Mar 2004 20:45 GMT >>>Hi, >>> [quoted text clipped - 16 lines] > different things? Extending Thread seems much cleaner, so what's the reason > for not? Many will argue that your LoggerThread is not logically a Thread any more because its purpose has been changed. A Thread exists to run Runnables, thus breathing life into an object. And it exists as a control-panel for a thread (lower case) of execution within the program.
On the other hand, a LoggerThread is intended to do no such thing. You are restricting its function, not extending it. To use a LoggerThread as a Thread should be used (i.e. creating it round a Runnable) would be against the design of LoggerThread. Different animals.
But I think the worst problem is the confusion it causes with beginners - the original post to this thread being one of many examples in this ng. In multi- threaded programs, having Threads call methods on other Threads (or their derivatives) and the interactions between object monitors becomes very confusing.
Steve
Ryan Stewart - 07 Mar 2004 14:25 GMT > >>>Hi, > >>> [quoted text clipped - 34 lines] > > Steve That makes sense. I can definitely see Thread being a consumer of Runnables. However, Thread itself implements Runnable. It seems that its creators intended it to be used this way. Maybe it should have been designed differently.
Steve Horsley - 08 Mar 2004 22:55 GMT > That makes sense. I can definitely see Thread being a consumer of Runnables. > However, Thread itself implements Runnable. It seems that its creators > intended it to be used this way. Maybe it should have been designed > differently. I wonder if there is some internal reason why Thread must be Runnable, but I think the most likely thing is that we are looking back with the 20/20 vision of hindsight. I think designing an API must be an order of magnitude harder than just learning to use it, as we mere mortals are doing.
Steve
FISH - 09 Mar 2004 12:15 GMT [snipped...]
> Many will argue that your LoggerThread is not logically a Thread any more > because its purpose has been changed. A Thread exists to run Runnables, thus [quoted text clipped - 5 lines] > Thread should be used (i.e. creating it round a Runnable) would be against > the design of LoggerThread. Different animals. Yes, but these more restrictive subclasses appear all the time in OO programming. Button extends Component in AWT, yet you cannot (legitimately) use Button as a blank canvas like you can with Component.
I agree, Thread gets overused (and I'm probably just as guilty as anyone!) Threading code should be looking to use Runnable most of the time - but there are odd occassions when extending Thread makes more sense, particularly when your class isn't a straight forward start->run->stop type afair.
I think if you try to stick too tightly to rules like "every subclass should be a more expressive version of its parent" then you can end up backing yourself into a lot of corners. The trick, of course, is to know when to obey rules, and when it makes more sense to bend them.
> But I think the worst problem is the confusion it causes with beginners - the > original post to this thread being one of many examples in this ng. In multi- > threaded programs, having Threads call methods on other Threads (or their > derivatives) and the interactions between object monitors becomes very > confusing. To be honest though, you will get that regardless of whether the class itself is a Thread subclass, or simply a Runnable which defers all the threading nitty-gritty. Using Runnable is not, as far as I'm aware, a silver bullet that makes interactions between threaded classes and monitors etc. any easier. Spagetti thread interactions are just as bad regardless of what construct you used to make the code threadable.
-FISH- ><
Steve Horsley - 10 Mar 2004 00:25 GMT > [snipped...] > [quoted text clipped - 13 lines] > backing yourself into a lot of corners. The trick, of course, is to > know when to obey rules, and when it makes more sense to bend them. Agreed.
>>But I think the worst problem is the confusion it causes with beginners - the >>original post to this thread being one of many examples in this ng. In multi- [quoted text clipped - 9 lines] > bad > regardless of what construct you used to make the code threadable. I have to disagree here, purely on the basis of the number of beginners I see posting here who are clearly having trouble keeping track of what is happening when Thread A is calling Thread B's methods:- who's instance variables are being used, and which object's monitor is being locked. I think the fact that your objects are Thread subclasses really does muddy the water. Yes I know it's simple when you get the hang of it, we're talking about people who are struggling to get their heads round both OO and multithreading at the same time.
Steve
Tony Morris - 06 Mar 2004 11:28 GMT > > > Hi, > > > [quoted text clipped - 16 lines] > different things? Extending Thread seems much cleaner, so what's the reason > for not? I concur with the other posts regarding Runnable/Thread. It is more useful to provide the ability for a class to directly extend some other class (other than java.lang.Object) if the need arises in the future (granted, if this does occur, something is likely to be wrong with the processes in place for design and implementation).
I'd also like to point out that, in practice, if I wrote a Runnable implementation that was so trivial that determining a name for it is frustrating, I usually don't bother naming it (by using an anonymous class). This is a general observation, rather than a convention - that is, just because a class name is not easily determined does not necessarily imply that it is a good reason to use an anonymous class.
 Signature Tony Morris (BInfTech, Cert 3 I.T., SCJP[1.4], SCJD) Software Engineer IBM Australia - Tivoli Security Software (2003 VTR1000F)
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|