Extending Thread and JComponent?

Chapter 4 - Implementing Runnable Versus Extending Thread

Java Thread Programming
Paul Hyde
  Copyright 1999 Sams Publishing

Checking the Accuracy of SecondCounter
During every iteration of the while loop of SecondCounterRunnable , a 100ms sleep is used to achieve the 1/10-second delay between each increment of the counter. What about the time it takes to execute the other statements in the loop? Does this cause the timer to be inaccurate? Probably, but is it significantly inaccurate? To find out, the modified class SecondCounterInaccurate , shown in Listing 4.5, keeps checking the systems real-time clock to find out whether the timer is drifting into inaccuracy by any measurable amount.
Listing 4.5  SecondCounterInaccurate.javaChecking the Timers Accuracy
1: import java.awt.*;
2: import javax.swing.*;
3: import java.text.*;
4:
5: public class SecondCounterInaccurate extends JComponent implements Runnable {
6:     private volatile boolean keepRunning;
7:     private Font paintFont;
8:     private volatile String timeMsg;
9:     private volatile int arcLen;
10:
11:     public SecondCounterInaccurate() {
12:         paintFont = new Font(SansSerif, Font.BOLD, 14);
13:         timeMsg = never started;
14:         arcLen = 0;
15:     }
16:
17:     public void run() {
18:         runClock();
19:     }
20:
21:     public void runClock() {
22:         DecimalFormat fmt = new DecimalFormat(0.000);
23:         long normalSleepTime = 100;
24:
25:         int counter = 0;
26:         long startTime = System.currentTimeMillis();
27:         keepRunning = true;
28:
29:         while (keepRunning) {
30:             try {
31:                 Thread.sleep(normalSleepTime);
32:             } catch (InterruptedException x) {
33:                 // ignore
34:             }
35:
36:             counter++;
37:             double counterSecs = counter / 10.0;
38:            double elapsedSecs =
39:                 (System.currentTimeMillis() - startTime) / 1000.0;
40:
41:             double diffSecs = counterSecs - elapsedSecs;
42:
43:             timeMsg = fmt.format(counterSecs) + - +
44:                     fmt.format(elapsedSecs) + = +
45:                     fmt.format(diffSecs);
46:
47:             arcLen = (((int) counterSecs) % 60) * 360 / 60;
48:             repaint();
49:         }
50:     }
51:
52:     public void stopClock() {
53:         keepRunning = false;
54:     }
55:
56:     public void paint(Graphics g) {
57:         g.setColor( Color .black);
58:         g.setFont(paintFont);
59:         g.drawString(timeMsg, 0, 15);
60:
61:         g.fillOval(0, 20, 100, 100);  // black border
62:
63:         g.setColor(Color.white);
64:         g.fillOval(3, 23, 94, 94);  // white for unused portion
65:
66:         g.setColor(Color.blue);  // blue for used portion
67:         g.fillArc(2, 22, 96, 96, 90, -arcLen);
68:     }
69: }
SecondCounterInacurrate is much the same as SecondCounterRunnable , with just a few additions to the runClock() method to measure the real time that has elapsed. In runClock() , before entering the while loop, the current system clock time in milliseconds is captured into a local variable, startTime (line 26). Each time through the loop, the elapsed time in seconds is calculated based on the system clock and stored into the local variable elapsedSecs (lines 38 and 39). The discrepancy in fractional seconds between the real-time system clock and the iteration count is calculated and stored in the local variable diffSecs (line 41). The text message to be drawn in paint() is expanded to include the formatted elapsedSecs and diffSecs values (lines 4345).
Listing 4.6 shows the code for SecondCounterInaccurateMain . The only differences between this code and the code for SecondCounterRunnableMain are the changes from using SecondCounterRunnable to SecondCounterInaccurate (lines 6, 7, 11, 12, 57, and 59).
Listing 4.6  SecondCounterInaccurateMain.javaCode to Use SecondCounterInaccurate
1: import java.awt.*;
2: import java.awt.event.*;
3: import javax.swing.*;
4: import javax.swing.border.*;
5:
6: public class SecondCounterInaccurateMain extends JPanel {
7:     private SecondCounterInaccurate sc;
8:     private JButton startB;
9:     private JButton stopB;
10:
11:     public SecondCounterInaccurateMain() {
12:         sc = new SecondCounterInaccurate();
13:         startB = new JButton(Start);
14:         stopB = new JButton(Stop);
15:
16:         stopB.setEnabled(false);  // begin with this disabled
17:
18:         startB.addActionListener(new ActionListener() {
19:                 public void actionPerformed(ActionEvent e) {
20:                     // disable to stop more start requests
21:                     startB.setEnabled(false);
22:
23:                     // thread to run the counter
24:                     Thread counterThread = new Thread(sc, SecondCounter);
25:                     counterThread.start();
26:
27:                     stopB.setEnabled(true);
28:                     stopB.requestFocus();
29:                 }
30:             });
31:
32:         stopB.addActionListener(new ActionListener() {
33:                 public void actionPerformed(ActionEvent e) {
34:                     stopB.setEnabled(false);
35:                     sc.stopClock();
36:                     startB.setEnabled(true);
37:                     startB.requestFocus();
38:                 }
39:             });
40:
41:         JPanel innerButtonP = new JPanel();
42:         innerButtonP.setLayout(new GridLayout(0, 1, 0, 3));
43:         innerButtonP.add(startB);
44:         innerButtonP.add(stopB);
45:
46:         JPanel buttonP = new JPanel();
47:         buttonP.setLayout(new BorderLayout());
48:         buttonP.add(innerButtonP, BorderLayout.NORTH);
49:
50:         this.setLayout(new BorderLayout(10, 10));
51:         this.setBorder(new EmptyBorder(20, 20, 20, 20));
52:         this.add(buttonP, BorderLayout.WEST);
53:         this.add(sc, BorderLayout.CENTER);
54:     }
55:
56:     public static void main(String[] args) {
57:         SecondCounterInaccurateMain scm = new SecondCounterInaccurateMain();
58:
59:         JFrame f = new JFrame(Second Counter Inaccurate);
60:         f.setContentPane(scm);
61:         f.setSize(320, 200);
62:         f.setVisible(true);
63:         f.addWindowListener(new WindowAdapter() {
64:                 public void windowClosing(WindowEvent e) {
65:                     System.exit(0);
66:                 }
67:             });
68:     }
69: }
Figure 4.9 presents three snapshots of SecondCounterInaccurateMain running. The first shows that after approximately a minute, the counter is off by 430ms. The second shows that after approximately 2 minutes, the counter is off by almost 1 second. The third shows that after approximately 3 minutes, the gap increased to 1.380 seconds.
Figure 4.9: The timer shows that it falls a bit more behind each minute.

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