Computing Pi


Building a Clock Component

Before we delve too deeply into the mechanics of threads, let’s start by thinking how we might create a Component that displays the current time every second. Our goal will be to write a self-contained Component that we might place into the interface of an application to display the current time to the nearest second. It should run in the background meaning that it shouldn’t take up all the computer’s CPU time. Getting the time and displaying it in a Component are simple enough, but how are we going to do it every second?

Example 16.3 prints the time to System.out every second but it’s not ideal. Before you run it, be aware that this program is an infinite loop, so you will have to manually kill the process that started it. Your development environment should provide a simple way to do this. Alternatively, Control-C (in Unix-based machines) or closing the command prompt window that started the process (in Windows) should do the trick.

Example 16.3: chap16.clock.Clock1.java

image from book
 1     package  chap16.clock; 2 3     import  java.text.DateFormat; 4     import  java.util.Date; 5 6     public   class  Clock1 { 7       public   static   void  main(String[] arg) { 8         Date date =  new  Date(); 9         DateFormat dateFormatter = DateFormat.getTimeInstance(); 10        String lastDateString = ""; 11 12        while (true) { 13          long currentMillis = System.currentTimeMillis(); 14          date.setTime(currentMillis); 15          String curDateString = dateFormatter.format(date); 16          if  (!lastDateString.equals(curDateString)) { 17            lastDateString = curDateString; 18            System.out.println(curDateString); 19          } 20        } 21      } 22    }
image from book

Use the following commands to compile the example. From the directory containing the src folder:

      javac –d classes -sourcepath src src/chap16/clock/Clock1.java      java –cp classes chap16.clock.Clock1

Will this program’s logic work for our background clock? No, it won’t because it keeps the CPU way too busy. No sooner does it compute the current time, compare it to the last computed time and perhaps print it to screen, than it immediately repeats the process. My computer goes through this compute/compare process more than 200,000 times before the second has changed and the current time needs to be printed again. This is quite a lot of effort for very little result. Unless it can rest for approximately one second between iterations, this thread will be less of a background process than a foreground process CPU hog. We will find a better way in the next section.

currentThread(), sleep(), interrupt(), interrupted() and isInterrupted()

The Thread class provides the static method, currentThread (listed in table 16-1), which returns a reference to the currently executing thread. The currently executing thread is necessarily the thread that is calling “Thread.currentThread()”. (Think about that if it didn’t make sense right away!) Many Thread methods are static because they are designed to affect only the current thread. In other words, invoking “whateverThread.someStaticMethod()” is equivalent to invoking “Thread.currentThread().someStaticMethod()” which is equivalent to invoking “Thread.someStaticMethod()”. The latter is the preferred way to call a static method as it minimizes possible ambiguity.

Table 16-1: Getting the Current Thread

Method Name and Purpose

public static Thread currentThread()

Returns a reference to the currently executing thread.

Thread.sleep() is one of those static methods that operate only on the current thread. Pass it a length of time measured in milliseconds, with an optional parameter of nanoseconds, and the current thread will cease execution until the time has elapsed or until it has been interrupted by another thread. Methods for sleeping and interrupting threads are listed in table 16-2.

Table 16-2: Sleeping and Interrupting

Method Name and Purpose

public static void sleep(long millis) throws InterruptedException

Causes the current thread to sleep for the specified number of milliseconds or until it has been interrupted.

public static void sleep(long millis, int nanos) throws InterruptedException

Causes the current thread to sleep for the specified number of milliseconds and additional nanoseconds or until it has been

interrupted.

public void interrupt()

Interrupts a thread that is sleeping or in another “waiting” mode. Otherwise it sets the thread’s interrupted status.

A thread interrupts another thread by invoking interrupt() on that thread as in:

 threadToInterrupt.interrupt();

If the interrupted thread was sleeping when it was interrupted, the sleep() method will throw an InterruptedException which the thread can catch and deal with as desired. If it wasn’t sleeping when it was interrupted, then the interrupted thread’s interrupted status will be set. A thread can check its interrupted status at any time by calling its isInterrupted() method or, if it’s the current thread, by calling the static interrupted() method. Calling interrupted() clears the current thread’s interrupted status. Calling isInterrupted() does not clear a thread’s interrupted status. These two methods are listed in table 16-3.

Table 16-3: Checking the Interrupted Status

Method Name and Purpose

public boolean isInterrupted()

Returns whether or not this thread has been interrupted. Does not clear its interrupted status.

public static boolean interrupted()

Returns whether or not the current thread has been interrupted and clears its interrupted status if it was set.

The following clock program (example 16.4) uses Thread.sleep() to tell the current thread to wait for the number of milliseconds until the time will have reached the next second before repeating the process. This is the logic we will need for a background clock.

Example 16.4: chap16.clock.Clock2.java

image from book
 1    package chap16.clock; 2 3    import java.text.DateFormat; 4    import java.util.Date; 5 6    public class Clock2 { 7      public static void main(String[] arg) { 8        Date date = new Date(); 9        DateFormat dateFormatter = DateFormat.getTimeInstance(); 10 11       while (true) { 12         long currentMillis = System.currentTimeMillis(); 13         date.setTime(currentMillis); 14         String curDateString = dateFormatter.format(date); 15         System.out.println(curDateString); 16         long sleepMillis = 1000 - (currentMillis % 1000); 17         try { 18           Thread.sleep(sleepMillis); 19         } catch (InterruptedException e) {} 20       } 21     } 22    }
image from book

Use the following commands to compile the example. From the directory containing the src folder:

      javac –d classes -sourcepath src src/chap16/clock/Clock2.java      java –cp classes chap16.clock.Clock2

Creating Your Own Threads

The thread class implements the Runnable interface which defines one method called run() that takes no parameters, returns no values and, as the javadocs state, “may take any action whatsoever”. There are basically two ways to create a Thread. One is to extend Thread and override its run() method to do whatever the thread is supposed to do. The other is to implement Runnable in another class, defining its run() method to do whatever the thread is supposed to do, and pass an instance of that class into the Thread’s constructor. If it was constructed with a Runnable parameter, Thread’s run() method will call the Runnable’s run() method. Optional parameters in the Thread constructors include the ThreadGroup to contain the Thread and a name for the Thread. All Threads have names which need not be unique. If a Thread is not assigned a name through its constructor, a name will be automatically generated for it. Except for the “main” thread which is started automatically by the JVM, all application created threads must be started by calling Thread.start(). This schedules the thread for execution. The JVM executes a thread by calling its run() method. Thread’s constructors are listed in table 16-4 and its start() and run() methods are listed in table 16-5.

Table 16-4: Thread Constructors

Constructor Method Names

public Thread()

public Thread(Runnable target)

public Thread(ThreadGroup group, Runnable target)

public Thread(String name)

public Thread(ThreadGroup group, String name)

public Thread(Runnable target, String name)

public Thread(ThreadGroup group, Runnable target, String name);

Table 16-5: Starting a Thread

Method Name and Purpose

public void start()

Causes the JVM to begin execution of this thread’s run method.

public void run()

There are no restrictions on what action the run method may take.

In the next program (examples 16.5 and 16.6), we extend Thread to define the ClockThread class. ClockThread’s constructor requires a Component parameter so that its run() method can call repaint() on it every second.

Example 16.5: chap16.clock.ClockThread.java

image from book
 1    package chap16.clock; 2 3    import java.awt.Component; 4 5    public class ClockThread extends Thread { 6      private Component component; 7 8      public ClockThread(Component component) { 9        this.component = component; 10       setName("Clock Thread"); 11     } 12     public void run() { 13       while (true) { 14         long currentMillis = System.currentTimeMillis(); 15         long sleepMillis = 1000 - (currentMillis % 1000); 16         component.repaint(); 17         try { 18           Thread.sleep(sleepMillis); 19         } catch (InterruptedException e) {} 20       } 21     } 22   }
image from book

Example 16.6: chap16.clock.ClockPanel1.java

image from book
 1     package chap16.clock; 2 3     import java.awt.BorderLayout; 4     import java.awt.Graphics; 5     import java.text.DateFormat; 6     import java.util.Date; 7 8     import javax.swing.JFrame; 9     import javax.swing.JLabel; 10    import javax.swing.JPanel; 11    import javax.swing.JScrollPane; 12    import javax.swing.JTextArea; 13 14    public class ClockPanel1 extends JPanel { 15      private final JLabel clockLabel; 16      private final DateFormat dateFormatter = DateFormat.getTimeInstance(); 17      private final Date date = new Date(); 18      private final Thread clockThread; 19 20      public ClockPanel1() { 21        clockLabel = new JLabel("Clock warming up...", JLabel.CENTER); 22        setLayout(new BorderLayout()); 23        add(clockLabel, BorderLayout.CENTER); 24        clockThread = new ClockThread(this); 25        clockThread.start(); 26      } 27      public void paintComponent(Graphics g) { 28        updateTime(); 29        super.paintComponent(g); 30      } 31      private void updateTime() { 32        long currentMillis = System.currentTimeMillis(); 33        date.setTime(currentMillis); 34        String curDateString = dateFormatter.format(date); 35        clockLabel.setText(curDateString); 36      } 37      public static void main(String[] arg) { 38        JFrame f = new JFrame(); 39        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 40        f.getContentPane().add(new ClockPanel1(), BorderLayout.NORTH); 41        f.getContentPane().add( 42          new JScrollPane(new JTextArea(20, 50)), 43          BorderLayout.CENTER); 44     45        f.pack(); 46        f.show(); 47      } 48    }
image from book

ClockPanel1 is a JPanel containing a JLabel. Its paintComponent() method is overridden so that whenever it is called, it will set the JLabel’s text to the current time. Its constructor creates an instance of ClockThread, passing itself as the component parameter, and starts the ClockThread. ClockPanel1’s “main” method constructs a simple JFrame that sports a running clock (a ClockPanel1) at the top and a JTextArea in its center. Each time the ClockThread calls repaint() on the ClockPanel1, the Swing framework is triggered to call paint(), which calls paintComponent() causing the displayed time to be updated.

Use the following commands to compile and run the example. From the directory containing the src folder:

    javac –d classes -sourcepath src src/chap16/clock/ClockPanel1.java    java –cp classes chap16.clock.ClockPanel1

ClockPanel2 (example 16.7) accomplishes the same thing as ClockPanel1, but without extending Thread. It implements Runnable instead. ClockPanel2’s constructor creates a new Thread object, passing itself in as the Runnable, and then starts the thread. Its run() method is identical to ClockThread’s run() method except that it calls repaint() on itself rather than another component.

Example 16.7: chap16.clock.ClockPanel2.java

image from book
 1     package chap16.clock; 2 3     import java.awt.BorderLayout; 4     import java.awt.Graphics; 5     import java.text.DateFormat; 6     import java.util.Date; 7 8     import javax.swing.JFrame; 9     import javax.swing.JLabel; 10    import javax.swing.JPanel; 11    import javax.swing.JScrollPane; 12    import javax.swing.JTextArea; 13 14    public class ClockPanel2 extends JPanel implements Runnable { 15      private final JLabel clockLabel; 16      private final DateFormat dateFormatter = DateFormat.getTimeInstance(); 17      private final Date date = new Date(); 18      private final Thread clockThread; 19 20      public ClockPanel2() { 21        clockLabel = new JLabel("Clock warming up...", JLabel.CENTER); 22        setLayout(new BorderLayout()); 23        add(clockLabel, BorderLayout.CENTER); 24        clockThread = new Thread(this); 25        clockThread.setName("Clock Thread"); 26        clockThread.start(); 27      } 28      public void paintComponent(Graphics g) { 29        updateTime(); 30        super.paintComponent(g); 31      } 32      private void updateTime() { 33        long currentMillis = System.currentTimeMillis(); 34        date.setTime(currentMillis); 35        String curDateString = dateFormatter.format(date); 36        clockLabel.setText(curDateString); 37      } 38      public void run() { 39        while (true) { 40          long currentMillis = System.currentTimeMillis(); 41          long sleepMillis = 1000 - (currentMillis % 1000); 42          repaint(); 43          try { 44            Thread.sleep(sleepMillis); 45          } catch (InterruptedException e) {} 46        } 47      } 48      public static void main(String[] arg) { 49        JFrame f = new JFrame(); 50        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 51        f.getContentPane().add(new ClockPanel2(), BorderLayout.NORTH); 52        f.getContentPane().add( 53          new JScrollPane(new JTextArea(20, 50)), 54          BorderLayout.CENTER); 55 56        f.pack(); 57        f.show(); 58      } 59    }
image from book

Use the following commands to compile and execute the example. From the directory containing the src folder:

      javac –d classes -sourcepath src src/chap16/clock/ClockPanel2.java      java –cp classes chap16.clock.ClockPanel2

Take time to run ClockPanel1 and/or ClockPanel2. Notice how the clock’s behavior is concurrent with and independent of user activity in the JTextArea. Incidentally, once the “main” thread has finished its work, the only threads remaining are the system threads, the Swing threads and the one thread running the clock.

Quick Review

A thread can be created by extending Thread and overriding its run method or by passing a Runnable into one of the standard Thread constructors. A thread must be started by calling its start() method. Calling Thread.sleep() causes a thread to stop executing for a certain length of time and frees the CPU for other threads. A sleeping thread can be woken by calling interrupt().




Java For Artists(c) The Art, Philosophy, and Science of Object-Oriented Programming
Java For Artists: The Art, Philosophy, And Science Of Object-Oriented Programming
ISBN: 1932504052
EAN: 2147483647
Year: 2007
Pages: 452

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