Interface java.lang.Runnable

Chapter 4 - Implementing Runnable Versus Extending Thread

Java Thread Programming
Paul Hyde
  Copyright 1999 Sams Publishing

Improving the Accuracy of SecondCounter
Although not many statements exist in the while loop, it has been shown that over time, they cause the loop to run significantly more slowly than desired. To improve the accuracy, the sleep time should be varied based on the current system clock time. The final version of SecondCounter is simply called SecondCounter ; its code appears in Listing 4.7.
Listing 4.7  SecondCounter.javaThe Most Accurate Timer
1: import java.awt.*;
2: import javax.swing.*;
3: import java.text.*;
4:
5: public class SecondCounter 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 SecondCounter() {
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:         long nextSleepTime = normalSleepTime;
25:
26:         int counter = 0;
27:         long startTime = System.currentTimeMillis();
28:         keepRunning = true;
29:
30:         while (keepRunning) {
31:             try {
32:                 Thread.sleep( nextSleepTime );
33:             } catch (InterruptedException x) {
34:                 // ignore
35:             }
36:
37:             counter++;
38:             double counterSecs = counter / 10.0;
39:             double elapsedSecs =
40:                 (System.currentTimeMillis() - startTime) / 1000.0;
41:
42:             double diffSecs = counterSecs - elapsedSecs;
43:
44:             nextSleepTime = normalSleepTime +
45:                     ((long) (diffSecs * 1000.0));
46:
47:             if (nextSleepTime < 0) {
48:                 nextSleepTime = 0;
49:             }
50:
51:             timeMsg = fmt.format(counterSecs) + - +
52:                     fmt.format(elapsedSecs) + = +
53:                     fmt.format(diffSecs);
54:
55:             arcLen = (((int) counterSecs) % 60) * 360 / 60;
56:             repaint();
57:         }
58:     }
59:
60:     public void stopClock() {
61:         keepRunning = false;
62:     }
63:
64:     public void paint(Graphics g) {
65:         g.setColor( Color .black);
66:         g.setFont(paintFont);
67:         g.drawString(timeMsg, 0, 15);
68:
69:         g.fillOval(0, 20, 100, 100);  // black border
70:
71:         g.setColor(Color.white);
72:         g.fillOval(3, 23, 94, 94);  // white for unused portion
73:
74:         g.setColor(Color.blue);  // blue for used portion
75:         g.fillArc(2, 22, 96, 96, 90, -arcLen);
76:     }
77: }
A new local variable named nextSleepTime is used to vary the number of milliseconds to sleep each time through the loop (lines 24 and 32). The nextSleepTime value is recalculated based on the difference between the counter seconds and the system clock seconds (lines 4245). If this value happens to be less than zero, zero is used instead because its impossible to sleep for a negative amount of time (lines 4749).
Listing 4.8 shows the code for SecondCounterMain . The only differences between this code and the code for SecondCounterInaccurateMain are the changes from using SecondCounterInaccurate to SecondCounter (lines 6, 7, 11, 12, 57, and 59).
Listing 4.8  SecondCounterMain.javaThe Supporting Code for SecondCounter
1: import java.awt.*;
2: import java.awt.event.*;
3: import javax.swing.*;
4: import javax.swing.border.*;
5:
6: public class SecondCounterMain extends JPanel {
7:     private SecondCounter sc;
8:     private JButton startB;
9:     private JButton stopB;
10:
11:     public SecondCounterMain() {
12:         sc = new SecondCounter();
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:         SecondCounterMain scm = new SecondCounterMain();
58:
59:         JFrame f = new JFrame(Second Counter);
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.10 presents three snapshots of the SecondCounterMain application running. The first shows that after approximately a minute, the counter and the actual time are perfectly synchronized. The next snapshot shows that after approximately 2 minutes, the counter is just 40ms ahead. After approximately 3 minutes, the counter time and the actual time are perfectly synchronized again. With this implementation, the SecondCounter continually corrects itself to the system clock, regardless of how quickly or slowly the other code in the loop executes.
Figure 4.10: The timer now stays very close to the accurate time.

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