Checking the Accuracy of SecondCounter

Chapter 5 - Gracefully Stopping Threads

Java Thread Programming
Paul Hyde
  Copyright 1999 Sams Publishing

Interrupting a Thread: interrupt()
While one thread is running, another thread can interrupt it by invoking its corresponding Thread objects interrupt() method:
public void interrupt()
This method simply sets a flag in the destination thread indicating that it has been interrupted and returns right away. It is possible that a SecurityException will be thrown by interrupt() , indicating that the thread requesting the interrupt does not have permission to interrupt the other thread. The security check is done by invoking the checkAccess() method on Thread , which in turn checks whether a SecurityManager has been installed, and if so, invokes its checkAccess(Thread) method. An in-depth exploration of security in Java is beyond the scope of this book, but you should note that some methods of Thread and ThreadGroup could throw SecurityException s.
  Caution SecurityException is a subclass of RuntimeException , so try / catch blocks are not required for any of the methods of Thread or ThreadGroup that might throw it. By default, an application does not have a SecurityManager defined (using JDK 1.0, 1.1, or 1.2 from Sun Microsystems). An applet, on the other hand, might have a SecurityManager present.
  In general, provisions are not made throughout the code to catch this type of exception, but a general precheck may be done early in the application or applet code. To check whether a SecurityManager is present, use the static method System.getSecurityManager() . If it returns null , a SecurityManager is not installed. If it is not null , caution must be used when invoking methods that might throw a SecurityException .
Interrupting a Sleeping Thread
Listing 5.1 shows how you can use interrupt() to disturb a sleeping thread and cause it to throw an InterruptedException .
Listing 5.1  SleepInterrupt.javaInterrupting a Sleeping Thread
1: public class SleepInterrupt extends Object implements Runnable {
2:     public void run() {
3:         try {
4:             System.out.println(
5:                     in run() - about to sleep for 20 seconds);
6:             Thread.sleep(20000);
7:             System.out.println(in run() - woke up);
8:         } catch (InterruptedException x) {
9:             System.out.println(
10:                     in run() - interrupted while sleeping);
11:             return;
12:         }
13:
14:         System.out.println(in run() - doing stuff after nap);
15:         System.out.println(in run() - leaving normally);
16:     }
17:
18:
19:     public static void main(String[] args) {
20:         SleepInterrupt si = new SleepInterrupt();
21:         Thread t = new Thread(si);
22:         t.start();
23:
24:         // Be sure that the new thread gets a chance to
25:         // run for a while.
26:         try { Thread.sleep(2000); }
27:         catch (InterruptedException x) { }
28:
29:         System.out.println(
30:                 in main() - interrupting other thread);
31:         t.interrupt();
32:         System.out.println(in main() - leaving);
33:     }
34: }
When SleepInterrupt is run, the following output occurs:
in run() - about to sleep for 20 seconds
in main() - interrupting other thread
in main() - leaving
in run() - interrupted while sleeping
Note that because of indeterminate thread scheduling, the last two lines might be swapped, but the first two will definitely appear in their current order.
After starting a second thread (line 22), the main thread proceeds to sleep for two seconds (line 26) to allow the new thread time to get up and running. The new thread prints its about to sleep message (lines 45) and proceeds to sleep for 20 seconds (line 6). About two seconds later, the main thread signals an interrupt to the new thread (line 31), prints its leaving message (line 32), and dies. Because it is interrupted, the new threads 20-second nap is abruptly stopped , with about 18 seconds remaining, and sleep() throws an InterruptedException (line 6). Execution jumps ahead to the catch block (line 8). The new thread prints its interrupted message (lines 910), returns right away from run() (line 11), and dies.
Pending Interrupts
The SleepInterrupt example shows that the implementation of the sleep() method is kind enough to stop sleeping and throw an InterruptedException if it detects that the sleeping thread is interrupted. Additionally, if an interrupt is pending before the sleep() method is called, it immediately throws an InterruptedException . This is demonstrated in PendingInterrupt , shown in Listing 5.2.
Listing 5.2  PendingInterrupt.javaAn Interrupt Can Occur Before It Is Checked For
1: public class PendingInterrupt extends Object {
2:     public static void main(String[] args) {
3:         if (args.length > 0) {
4:             Thread.currentThread().interrupt();
5:         }
6:
7:         long startTime = System.currentTimeMillis();
8:         try {
9:             Thread.sleep(2000);
10:             System.out.println(was NOT interrupted);
11:         } catch (InterruptedException x) {
12:             System.out.println(was interrupted);
13:         }
14:
15:         System.out.println(
16:                 elapsedTime= + (System.currentTimeMillis() - startTime));
17:     }
18: }
If PendingInterrupt is run without any command-line arguments, as follows ,
java PendingInterrupt
it produces output much like this:
was NOT interrupted
elapsedTime=2080
In this mode, it simply sleeps for the specified two seconds and prints out the message that it was not interrupted. Alternatively, if PendingInterrupt is run with any command-line arguments, as follows,
java PendingInterrupt yes
it would instead produce output much like this:
was interrupted
elapsedTime=110
In this mode, the main thread interrupts itself (line 4). This does not have any effect other than setting an interrupted flag (which is internal to Thread ) to true . Although interrupted, the main thread keeps running. The main thread proceeds to make note of the current real-time clock (line 7) and enters the try block (line 8). As soon as the sleep() is invoked (line 9), it notices that there is a pending interrupt and immediately throws an InterruptedException . Execution jumps to the catch block (line 11) and prints the message that the thread was interrupted. Finally, the elapsed time is calculated and printed.
Using isInterrupted()
You can check the interrupted status of any thread by invoking the isInterrupted() method on the Thread object:
public boolean isInterrupted()
This does not alter the status, but simply returns true if the thread has been interrupted and its interrupted flag has not yet been cleared. Listing 5.3 shows an example of how you can use isInterrupted() .
Listing 5.3  InterruptCheck.javaUsing isInterrupted()
1: public class InterruptCheck extends Object {
2:     public static void main(String[] args) {
3:         Thread t = Thread.currentThread();
4:         System.out.println(Point A: t.isInterrupted()= + t.isInterrupted());
5:         t.interrupt();
6:         System.out.println(Point B: t.isInterrupted()= + t.isInterrupted());
7:         System.out.println(Point C: t.isInterrupted()= + t.isInterrupted());
8:
9:         try {
10:             Thread.sleep(2000);
11:             System.out.println(was NOT interrupted);
12:         } catch (InterruptedException x) {
13:             System.out.println(was interrupted);
14:         }
15:
16:         System.out.println(Point D: t.isInterrupted()= + t.isInterrupted());
17:     }
18: }
Running InterruptCheck produces the following output:
Point A: t.isInterrupted()=false
Point B: t.isInterrupted()=true
Point C: t.isInterrupted()=true
was interrupted
Point D: t.isInterrupted()=false
Initially, at Point A, the interrupted status is false (line 4), and it is set to true by invoking interrupt() (line 5). As a result, at Point B, isInterrupted() now returns true (line 6). At Point C, isInterrupted() still returns true and is unaffected by a previous call. Because the interrupted flag is true , sleep() immediately throws an InterruptedException (line 10). Execution jumps to the catch and prints a message indicating that the thread was interrupted (line 13). Finally, at Point D, isInterrupted() returns false because the interrupted flag was cleared by sleep() when it threw the exception.
Using Thread.interrupted()
You can use the Thread.interrupted() method to check (and implicitly reset to false ) the interrupted status of the current thread:
public static boolean interrupted()
Because it is static , it cannot be invoked on a particular thread, but can only report the interrupted status of the thread that invoked it. This method returns true if the thread has been interrupted and its interrupted flag has not yet been cleared. Unlike isInterrupted() , it automatically resets the interrupted flag to false . Invoking Thread.interrupted() a second time would always return false unless the thread was reinterrupted. Listing 5.4 shows an example of how you can use Thread.interrupted() .
Listing 5.4  InterruptReset.javaUsing Thread.interrupted()
1: public class InterruptReset extends Object {
2:     public static void main(String[] args) {
3:         System.out.println(
4:             Point X: Thread.interrupted()= + Thread.interrupted());
5:         Thread.currentThread().interrupt();
6:         System.out.println(
7:             Point Y: Thread.interrupted()= + Thread.interrupted());
8:         System.out.println(
9:             Point Z: Thread.interrupted()= + Thread.interrupted());
10:     }
11: }
Running InterruptReset produces the following output:
Point X: Thread.interrupted()=false
Point Y: Thread.interrupted()=true
Point Z: Thread.interrupted()=false
Initially, at Point X, the interrupted status is false (lines 34). The current thread interrupts itself on line 5. At Point Y, the interrupted status is true and is automatically reset back to false by Thread.interrupted() (lines 67). The final check of the status at Point Z shows that it is indeed false again (lines 89).
Using InterruptedException
A method such as Thread.sleep() is kind enough to stop sleeping and throw an InterruptedException if it is interrupted. Another method commonly used in multithreaded programming is the wait() method of Object . It is involved with inter-thread communication and is covered in detail in Chapter 8, Inter-thread Communication. Like Thread.sleep() , it, too, throws an InterruptedException if interrupted. Many other methods in the JDK will throw an InterruptedException if the thread that entered the method is interrupted before completing its work.
The pattern of throwing an InterruptedException when interrupted by another thread is a useful one to extend to other customized methods. For example, imagine that you need a method that performs a complex and long-running calculation. It would be nice if the calculation occasionally checked whether it had been interrupted and if it had, threw an InterruptedException to stop the calculation and indicate that it did not complete normally.
Listing 5.5 shows an example of how the interrupted status can be checked and used to throw an InterruptedException if necessary. When run, the class PiInterrupt proceeds to iterate continuously to calculate the special number pi until the desired level of accuracy is achievedor until it is interrupted.
Listing 5.5  PiInterrupt.javaThrowing InterruptedException When Necessary
1: public class PiInterrupt extends Object implements Runnable {
2:     private double latestPiEstimate;
3:
4:     public void run() {
5:         try {
6:             System.out.println(for comparison, Math.PI= +
7:                                 Math.PI);
8:             calcPi(0.000000001);
9:             System.out.println(within accuracy, latest pi= +
10:                                 latestPiEstimate);
11:         } catch (InterruptedException x) {
12:             System.out.println(INTERRUPTED!! latest pi= +
13:                                 latestPiEstimate);
14:         }
15:     }
16:
17:     private void calcPi(double accuracy)
18:                 throws InterruptedException {
19:
20:         latestPiEstimate = 0.0;
21:         long iteration = 0;
22:         int sign = -1;
23:
24:         while (Math.abs(latestPiEstimate - Math.PI) >
25:                 accuracy) {
26:
27:             if (Thread.interrupted()) {
28:                 throw new InterruptedException();
29:             }
30:
31:             iteration++;
32:             sign = -sign;
33:             latestPiEstimate +=
34:                     sign * 4.0 / ((2 * iteration) - 1);
35:         }
36:     }
37:
38:     public static void main(String[] args) {
39:         PiInterrupt pi = new PiInterrupt();
40:         Thread t = new Thread(pi);
41:         t.start();
42:
43:         try {
44:             Thread.sleep(10000);
45:             t. interrupt ();
46:         } catch (InterruptedException x) {
47:             // ignore
48:         }
49:     }
50: }
In the main thread, a new PiInterrupt instance is constructed (line 39). Because PiInterrupt implements Runnable , an instance of it can be passed to the constructor for Thread (line 40). The new Thread object is started (line 41). The main thread then proceeds to sleep for 10 seconds (line 44) before interrupting the thread running inside PiInterrupt .
While the main thread is sleeping, the newly spawned thread enters the run() method (line 4). For comparison purposes, it prints out the value of pi held as a constant in the Math class (lines 67). It then proceeds to call calcPi() , specifying that it should continue to refine its calculation until it is within 0.000000001 of the constant Math.PI (line 8).
The private method calcPi() declares that it might throw an InterruptedException (line 18). It will do this if interrupted before getting within the specified accuracy. The technique used to calculate pi is to sum the terms of the infinite series
pi = 4/1 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 + 4/13 - 4/15 ...
for as long as necessary to get within the specified accuracy. The while loop continues as long as the absolute value of the difference between the calculated pi and the constant stored in Math.PI differ more than the desired accuracy (lines 2425). Each time through the loop, the interrupted flag is checked and reset to false (line 27). If the flag was true before being reset, an InterruptedException is thrown (line 28) and the method stops calculating. If the flag was false before being reset, the estimate is further refined (lines 3134) and the while loop continues.
If the desired accuracy is reached before the interrupt, flow returns to run() , and the estimated pi value is printed (lines 910). If the thread is interrupted before reaching the desired accuracy, the exception is thrown and flow jumps to the catch block (line 11) where the estimate pi value is printed (lines 1213).
When PiInterrupt is run, output such as the following should be produced:
for comparison, Math.PI=3.141592653589793
INTERRUPTED!! latest pi=3.141592091246143
In this case, the calculation took too long and was interrupted after 10 seconds. If your machine is fast enough to get within the accuracy before 10 seconds has elapsed, reduce the sleep time (by perhaps 2 seconds), recompile, and run it again.
  Tip In long-running methods, consider using this technique of checking the interrupted status and throwing an InterruptedException when necessary. It is a nice way of allowing a long-running method to be cancelled by another thread.

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