|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 4 of 7
Ten years ago on JavaWorld, Dave Dyer noted that the Java language had one feature so "pervasively used incorrectly" that he ranked it as a serious design flaw. That feature was multithreading.
Dyer's comment highlights the challenge of testing multithreaded programs. When you can no longer easily specify the output of a program in terms of a definite sequence of characters, there will be an impact on how effectively you can test your threaded code.
The correct starting point to resolving the intrinsic difficulties of concurrent programming was well stated by Heinz Kabutz
in his Java Specialist newsletter: recognize that concurrency is a topic that you should understand and study it systematically. There are of course
tools such as diagramming techniques and formal languages that will help. But the first step is to sharpen your intuition
by practicing with simple programs like FirstThreadingExample in Listing 1. Next, learn as much as you can about threading fundamentals like these:
Object orientation in Java defines singly inherited classes, which has consequences for multithreading coding. To this point,
I have only described a use for Thread that was based on subclasses with an overridden run(). In an object design that already involved inheritance, this simply wouldn't work. You cannot simultaneously inherit from
RenderedObject or ProductionLine or MessageQueue alongside Thread!
This constraint affects many areas of Java, not just multithreading. Fortunately, there's a classical solution for the problem,
in the form of the Runnable interface. As explained by Jeff Friesen in his 2002 introduction to threading, the Runnable interface is made for situations where subclassing Thread isn't possible:
TheRunnableinterface declares a single method signature:void run();. That signature is identical toThread'srun()method signature and serves as a thread's entry of execution. BecauseRunnableis an interface, any class can implement that interface by attaching animplementsclause to the class header and by providing an appropriaterun()method. At execution time, program code can create an object, or runnable, from that class and pass the runnable's reference to an appropriateThreadconstructor.
So for those classes that cannot extend Thread, you must create a runnable to take advantage of multithreading. Semantically, if you're doing system-level programming and
your class is in an is-a relation to Thread, then you should subclass directly from Thread. But most application-level use of multithreading relies on composition, and thus defines a Runnable compatible with the application's class diagram. Fortunately, it takes only an extra line or two to code using the Runnable interface, as shown in Listing 3 below.
Threads programming
Thread synchronization
Locks and monitors
Testing and debugging threads
Threads & alternatives