Finding All the Threads in a Thread Group

Chapter 11 - Self-Running Objects

Java Thread Programming
Paul Hyde
  Copyright 1999 Sams Publishing

Additional Functionality to Consider
You can extend the concept of a self-running object to allow more details about the internal thread to be specified:
  A ThreadGroup for the internal thread can be passed to the classs constructor and then passed to the Thread constructor.
  A name for the internal thread can be passed to the classs constructor and then passed to the Thread constructor.
  The methods getInternalThreadName() and setInternalThreadName() can be added if desired. They would simply proxy the request to the underlying thread internalThread .
  A priority for the internal thread can be passed to the classs constructor and then internalThread.setPriority() can be invoked before the thread is started.
  The methods getInternalThreadPriority() and setInternalThreadPriority() can be added if desired. They would simply proxy the request to internalThread .
  If its inappropriate for the internal thread to be started in the constructor, a new method can be added to allow it to be started later:
public void start() {
    if (neverStarted) {
        neverStarted = false;
        internalThread.start();
    }
}
  The suspendRequest() and resumeRequest() techniques of Chapter 5, Gracefully Stopping Threads, can be added if needed.
Example: Animated Images on a JComponent
In this example, Ill show you how to animate a set of images using a customized JComponent that automatically runs a thread inside itself to flip through the images. The images are generated at construction time, but you can modify this design to animate images from any source: computer-generated or from a set of files.
The customized component Squish , shown in Listing 11.5, draws the top half of an ellipse with successively smaller heights. It appears that a mound is being squished down until it is flat. Then the cycle starts over with the full-height, top-half ellipse. The work to animate the images is transparent to the user of the class as the component creates its own internal thread to flip through the images.
Listing 11.5  Squish.javaThe Animated Image Component
  1: import java.awt.*;
  2: import java.awt.image.*;
  3: import java.awt.geom.*;
  4: import javax.swing.*;
  5:
  6: public class Squish extends JComponent {
  7:     private Image[] frameList;
  8:     private long msPerFrame;
  9:     private volatile int currFrame;
10:
11:     private Thread internalThread;
12:     private volatile boolean noStopRequested;
13:
14:     public Squish(
15:                 int width,
16:                 int height,
17:                 long msPerCycle,
18:                 int framesPerSec,
19:                 Color fgColor
20:            ) {
21:
22:         setPreferredSize(new Dimension(width, height));
23:
24:         int framesPerCycle =
25:                 (int) ((framesPerSec * msPerCycle) / 1000);
26:         msPerFrame = 1000L / framesPerSec;
27:
28:         frameList =
29:             buildImages(width, height, fgColor, framesPerCycle);
30:         currFrame = 0;
31:
32:         noStopRequested = true;
33:         Runnable r = new Runnable() {
34:                 public void run() {
35:                     try {
36:                         runWork();
37:                     } catch (Exception x) {
38:                         // in case ANY exception slips through
39:                         x.printStackTrace();
40:                     }
41:                 }
42:             };
43:
44:         internalThread = new Thread(r);
45:         internalThread.start();
46:     }
47:
48:     private Image[] buildImages(
49:                 int width,
50:                 int height,
51:                 Color color,
52:                 int count
53:            ) {
54:
55:         BufferedImage[] im = new BufferedImage[count];
56:
57:         for (int i = 0; i < count; i++) {
58:             im[i] = new BufferedImage(
59:                     width, height, BufferedImage.TYPE_INT_ARGB);
60:
61:             double xShape = 0.0;
62:             double yShape =
63:                 ((double) (i * height)) / (double) count;
64:
65:             double wShape = width;
66:             double hShape = 2.0 * (height - yShape);
67:             Ellipse2D shape = new Ellipse2D.Double(
68:                         xShape, yShape, wShape, hShape);
69:
70:             Graphics2D g2 = im[i].createGraphics();
71:             g2.setColor(color);
72:             g2.fill(shape);
73:             g2.dispose();
74:         }
75:
76:         return im;
77:     }
78:
79:     private void runWork() {
80:         while (noStopRequested) {
81:             currFrame = (currFrame + 1) % frameList.length;
82:             repaint();
83:
84:             try {
85:                 Thread.sleep(msPerFrame);
86:             } catch (InterruptedException x) {
87:                 // reassert interrupt
88:                 Thread.currentThread().interrupt();
89:                 // continue on as if sleep completed normally
90:             }
91:         }
92:     }
93:
94:     public void stopRequest() {
95:         noStopRequested = false;
96:         internalThread.interrupt();
97:     }
98:
99:     public boolean isAlive() {
100:         return internalThread.isAlive();
101:     }
102:
103:     public void paint(Graphics g) {
104:         g.drawImage(frameList[currFrame], 0, 0, this);
105:     }
106: }
Squish extends JComponent so that it can inherit the functionality of a generic Swing component (line 6). Notice that although it will be running an internal thread, it does not implement the Runnable interface (line 6). This example uses the technique of hiding run() in an anonymous, inner class.
The set of images to animate is held in Image array frameList (line 7). The number of milliseconds that each frame should be shown before flipping to the next one is held in msPerFrame (line 8). The current index into the frameList is held in the volatile member variable currFrame (line 9). It is marked as volatile because it is modified by the internal thread inside runWork() (line 81), and read by the event-handling thread inside paint() (line 104). The thread running inside this component is referenced by internalThread (line 11). The flag indicating whether or not a stop has been requested is held in noStopRequested (line 12).
The constructor (lines 1446) takes several parameters. The components width in pixels is passed in through width (line 15). Its height is passed in through height (line 16). The number of milliseconds it should take for the mound to be squished down from its full height is specified through msPerCycle (line 17). The number of frames to be flipped though per second is framesPerSec (line 18). The higher the frames per second rate is (up to about 30 fps), the smoother the animation appears, but the greater the demand on the processor. The last parameter fgColor (line 19) is simply the color with which the mound should be drawn.
The preferred size for this component is simply the combination of the width and height passed in (line 22). The number of images to generate for a full cycle from tall to flat is calculated based on the passed-in parameters (lines 2425). The time that each frame should be shown for is calculated (line 26). The images to use are computer generated and stored in frameList (lines 2829), and the index into this list is initialized to be (line 30). The rest of the constructor (lines 3245) implements the standard internal thread pattern I showed you earlier in this chapter.
The buildImages method (lines 4877) creates all of the frames to be flipped though during animation. A set of BufferedImage objects is created and drawn onto using Graphics2D methods. This set of images is returned to the caller, which in this case is the constructor.
Control of which frame to display is managed inside runWork() (lines 7992). Each time through the while loop, a check is done to see if a stop has been requested (line 80). If not, the frame number is incremented and wrapped around back to if the last frame has been shown (line 81). After the frame number advances, a repaint request is submitted to the event queue so that the new frame is drawn as soon as possible (line 82). Before looping again, the internal thread sleeps for the interframe interval (line 85). If this sleep is interrupted (probably by stopRequest() ), the InterruptedException is caught (line 86). As a matter of good style, the internal thread is reinterrupted (line 88) in case any other interruptible, blocking statements are encountered before the thread gets a chance to die.
The stopRequest() method simply sets the noStopRequested flag to false (line 95) and interrupts the internal thread (line 96) in case it is blocked on an interruptible statement. In this example, the internal thread spends most of its time blocked sleeping, and the interrupt will wake it up early to take notice of the stop request. The isAlive() method is used after a stopRequest() call to check if the thread has died yet.
The paint() method (lines 103105) is invoked by the event handling thread whenever there has been a request to repaint the component. In this case, paint simply draws the image indicated by currFrame onto the component (line 104).
The class SquishMain , shown in Listing 11.6, creates support containers to demonstrate the functionality of two Squish components .
Listing 11.6  SquishMain.javaCode to Demonstrate the Use of Squish
1: import java.awt.*;
2: import java.awt.event.*;
3: import javax.swing.*;
4:
5: public class SquishMain extends JPanel {
6:     public SquishMain() {
7:         Squish blueSquish = new Squish(150, 150, 3000L, 10, Color.blue);
8:         Squish redSquish = new Squish(250, 200, 2500L, 10, Color.red);
9:
10:         this.setLayout(new FlowLayout());
11:         this.add(blueSquish);
12:         this.add(redSquish);
13:     }
14:
15:     public static void main(String[] args) {
16:         SquishMain sm = new SquishMain();
17:
18:         JFrame f = new JFrame(Squish Main);
19:         f.setContentPane(sm);
20:         f.setSize(450, 250);
21:         f.setVisible(true);
22:         f.addWindowListener(new WindowAdapter() {
23:                 public void windowClosing(WindowEvent e) {
24:                     System.exit(0);
25:                 }
26:             });
27:     }
28: }
In main() (lines 1527), a new SquishMain object is constructed (line 16) and placed into the content pane of a JFrame (line 19). The frame is sized and made visible (lines 2021). Event-handling code is added to the frame so that when its Close control is clicked, the VM will exit (lines 2226).
The SquishMain class is a subclass of JPanel (line 5) so that it can have components added to it. In the constructor (lines 613), two Squish components are constructed: one blue, and one red (lines 78). Because the Squish components each automatically start an internal thread to animate themselves , no further action is required to use them other than simply constructing them! The objects are a subclass of JComponent and are simply added to the panel within a FlowLayout (lines 1012).
Figures 11.1 and 11.2 show two snapshots of SquishMain in action.
Figure 11.1: Snapshot of SquishMain running with both mounds relatively tall.
Figure 11.2: Another snapshot of SquishMain running, this time with both mounds a bit flatter.

Toc


Java Thread Programming
Java Thread Programming
ISBN: 0672315858
EAN: 2147483647
Year: 2005
Pages: 149
Authors: Paul Hyde

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net