| Multithreading |
|
| Introduction: |
|
| Multithreading is a fundamental feature of the Java language specification. The creators of Java understood the importance of multithreading and provided easy to use features for application developers. Two of these features, the Thread class and the Runnable interface, will be covered shortly. |
|
| Multithreading is not the same as multiprocessing. The latter involves the use of two or more processors (CPUs). Multithreading involves the sharing of a single processor and the interleaving of CPU time as shown by the following diagram: |
|
|
|
|
| Because there is only one processor, only one instruction can be executed at a time. In a Java program, the decision as to which thread is currently executing is determined by the JVM. |
|
| Multithreading is used to execute even the simplest Java program. Even if a program doesn't create its own threads, the Java Virtual Machine creates multiple threads to support the program. One thread performs the processing of the main() method. Other threads manage and monitor system resources. The garbage collector, for example, is always running as a low-priority thread. |
|
|
|
|
|
|
| Multithreading |
|
| Thread |
|
| A thread--sometimes known as an execution context or a lightweight process--is a single sequential flow of control within a process. |
|
|
| Definition: |
| A thread is a single sequential flow of control within a program |
|
| Example: |
| The following program is a simple Java application that creates and starts two independent threads: |
|
class TwoThreadsTest
{
public static void main (String[] args)
{
new SimpleThread("Jamaica").start();
new SimpleThread("Fiji").start();
}
}
class SimpleThread extends Thread
{
public SimpleThread(String str)
{
super(str);
}
public void run() {
for (int i = 0; i < 10; i++)
{
System.out.println(i + " " + getName());
try
{
sleep((int)(Math.random() * 1000));
}
catch (InterruptedException e)
{
}
}
System.out.println("DONE! " + getName());
}
} |
|
|
| A thread is similar to the sequential programs described above: a single thread also has a beginning, an end, a sequence, and at any given time during the runtime of the thread there is a single point of execution. |
|
|
| The HotJava Web browser is an example of a multithreaded application. Within the HotJava browser we can scroll a page while it's downloading an applet or image, play animation and sound concurrently, print a page in the background while we download a new page, or watch three sorting algorithms race to the finish. |
|
|
|
|
|
| Multithreading |
|
| Thread Attributes |
|
| Java threads are implemented by the Thread class, which is part of the java.lang package. The Thread class implements a system independent definition of Java threads. But under the hood, the actual implementation of concurrent operation is provided by a system-specific implementation. |
|
| The life of a thread |
| In Java, all threads are objects that are constructed, pass between several "states", and die in keeping with the following diagram: |
|
|
|
|
|
| 1. When initially constructed, the thread is New |
|
| 2. When all resources the thread requires are available, it enters the Ready state. The thread is ready to use the CPU. |
|
| 1. When selected by the JVM for processing, the thread enters the Running state. This is the state that all threads aspire to but only one is ever running at an instant in time. |
|
| 2. When the thread requests to sleep for an interval of time, must wait for a resource (such as completion of I/O), or is suspended by the JVM, it becomes Blocked. It gives up the CPU and will return to the Ready state when the block is removed. |
|
| 3. When the thread completes its processing or is killed by the JVM, it enters the Dead state. The thread object will still exist, but will no longer be allowed to use the CPU. |
|
|
| Thread Body |
| All of the action takes place in the thread's body--the thread's run() method. We can provide the body to a Thread in one of two ways: |
| a. by subclassing the Thread class and overriding its run() method, |
|
| b. by creating a Thread with a Runnable object as its target. |
|
|
| Creating the Thread |
| The application in which an applet is running calls the applet's start() method when the user visits the applet's page. |
| The Clock applet creates a Thread, clockThread, in its start() method and starts the thread. |
|
public void start()
{
if (clockThread == null)
{
clockThread = new Thread(this, "Clock");
clockThread.start();
}
} |
|
| First, the start() method checks to see if clockThread is null. If clockThread is null, then the applet has just been loaded or has been previously stopped and a new thread must be created. |
|
| Otherwise, the applet is already running. The applet creates a new thread with this invocation: |
| clockThread = new Thread(this, "Clock"); |
|
| Here--the Clock applet--is the first argument to the thread constructor. The first argument to this Thread constructor must implement the Runnable interface and becomes the thread's target. When constructed in this way, the clock thread gets its run() method from its target Runnable object--in this case, the Clock applet. |
|
| The second argument is just a name for the thread. |
|
| After a thread has been created and initialized, the runtime system calls its run() method. The code in the run() method implements the behavior for which the thread was created. |
|
|
| Stopping the Thread |
| When we leave the page that displays the Clock applet, the application in which the applet is running calls the applet's stop() method. |
| The Clock's stop() method sets the clockThread to null. |
| This tells the main loop in the run() method to terminate eventually resulting in the thread stopping and being garbage collected. |
public void stop()
{
clockThread = null;
} |
|
| we can use clockThread.stop() instead, which would immediately stop the clock thread. |
| However, the Thread class's stop() method has a sudden effect, which means that the run() method might be in the middle of some critical operation when the thread is stopped. |
| For more complex run() methods, using Thread's stop() method might leave the program in an inconsistent or awkward state. For this reason, it's best to avoid using the Thread class's stop() method when possible. |
|
| If we revisit the page, the start() method is called again, and the clock starts up again with a new thread. |
|
|
| The Run Method |
| And finally the Clock's run() method implements the heart of the Clock applet and looks like this: |
|
public void run()
{
// loop terminates when clockThread is set to null in stop()
while (Thread.currentThread() == clockThread)
{
repaint();
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
}
} |
|
|
|
|
|
| Multithreading |
|
| Thread State |
|
| Throughout its life, a Java thread is in one of several states. A thread's state indicates what the Thread is doing and what it is capable of doing at that time of its life: is it running? Is it sleeping? Is it dead? |
|
|
|
|
| The above diagram illustrates the various states that a Java thread can be in at any point during its life. It also illustrates which method calls cause a transition to another State. |
|
|
| New Thread |
| The following statement creates a new thread but does not start it, thereby leaving the thread in the "New Thread" state. |
| Thread myThread = new MyThreadClass(); |
|
|
| When a thread is in the "New Thread" state, it is merely an empty Thread object. No system resources have been allocated for it yet. Thus when a thread is in this state, we can only start the thread or stop it. Calling any method besides start() or stop() when a thread is in this state makes no sense and causes an IllegalThreadstateException. |
|
|
| Runnable |
| Now consider these two lines of code: |
Thread myThread = new MyThreadClass();
myThread.start(); |
|
| The start() method creates the system resources necessary to run the thread, schedules the thread to run, and calls the thread's run() method. At this point the thread is in the"Runnable" state. This state is called "Runnable" rather than "Running" because the thread might not actually be running when it is in this state. Many computers have a single processor, making it impossible to run all "Runnable" threads at the same time. So, the Java runtime system must implement a scheduling scheme that shares the processor between all "Runnable" threads. |
|
|
| Not Runnable |
| A thread enters the "Not Runnable" state when one of these four events occurs: |
| 1. Someone invokes its sleep() method. |
| 2. Someone invokes its suspend() method. |
| 3. The thread uses its wait() method to wait on a condition variable. |
| 4. The thread is blocking on I/O. |
|
| For example, |
| The bold line in the following code snippet puts the current thread to sleep for 10 seconds (10,000 milliseconds): |
|
try
{
Thread.sleep(10000);
} catch (InterruptedException e)
{
} |
|
| During the 10 seconds that myThread is asleep; even if the processor becomes available myThread does not run. After the 10 seconds are up, myThread becomes "Runnable"again and, if the processor becomes available, runs. |
|
| If a thread has been put to sleep, then the specified number of milliseconds must elapse before the thread becomes "Runnable" again. Calling resume() on a sleeping thread has no effect. |
|
| The following indicates the escape route for every entrance into the "Not Runnable" state. |
| 1. If a thread has been put to sleep, then the specified number of milliseconds must elapse. |
| 2. If a thread has been suspended, then someone must call its resume() method. |
| 3. If a thread is waiting on a condition variable, whatever object owns the variable must relinquish it by calling either notify() or notifyAll(). |
| 4. If a thread is blocked on I/O, then the I/O must complete. |
|
|
| Dead |
| A thread can die in two ways: either from natural causes, or by being killed (stopped). A thread dies naturally when its run() method exits normally. |
| For example, |
| The while loop in this method is a finite loop--it will iterate 100 times and then exit. |
|
public void run()
{
int i = 0;
while (i < 100)
{
i++;
System.out.println("i = " + i);
} } |
|
| A thread with this run() method will die naturally after the loop and the run() method completes. |
|
| We can also kill a thread at any time by calling its stop() method. |
| The following code snippet creates and starts myThread then puts the current thread to sleep for 10 seconds. When the current thread wakes up, the bold line in the code segment kills myThread. |
|
Thread myThread = new MyThreadClass();
myThread.start();
try
{
Thread.sleep(10000);
} catch (InterruptedException e)
{
}
myThread.stop(); |
|
| The stop() method throws a ThreadDeath object at the thread to kill it. Thus when a thread is killed in this manner it dies asynchronously. The thread will die when it actually receives the ThreadDeath exception. |
|
|
| IllegalThreadStateException |
| The runtime system throws an IllegalThreadStateException when we call a method on a thread and that thread's state does not allow for that method call. |
|
| For example, |
| IllegalThreadStateException is thrown when we invoke suspend() on a thread that is not"Runnable". |
|
|
| The isAlive() Method |
| A final word about thread state: the programming interface for the Thread class includes a method called isAlive(). |
| The isAlive() method returns true if the thread has been started and not stopped. |
| Thus, if the isAlive() method returns false we know that the thread is either a "New Thread" or "Dead". |
| If the isAlive() method returns true, we know that the thread is either "Runnable" or "Not Runnable". |
| We cannot differentiate between a "New Thread" and a "Dead" thread; nor can we differentiate between a "Runnable" thread and a "Not Runnable" thread. |
|
|
| Thread Priority |
| A thread's priority tells the Java thread scheduler when this thread should run in relation to other threads. |
|
| Some points |
| 1. Most computers have only one CPU, thus threads must share the CPU with other threads. The execution of multiple threads on a single CPU, in some order, is called scheduling. The Java runtime supports a very simple, deterministic scheduling algorithm known as fixed priority scheduling. |
|
| 2. Each Java thread is given a numeric priority between MIN_PRIORITY and MAX_PRIORITY (constants defined in class Thread). At any given time, when multiple threads are ready to be executed, the thread with the highest priority will be chosen for execution. Only when that thread stops, or is suspended for some reason, will a lower priority thread start executing. |
|
| 3. Scheduling of the CPU is fully preemptive. If a thread with a higher priority than the currently executing thread needs to execute, the higher priority thread is immediately scheduled. |
|
| 4. The Java runtime will not preempt the currently running thread for another thread of the same priority. In other words, the Java runtime does not time-slice. However, the system implementation of threads underlying the Java Thread class may support time-slicing. Do not write code that relies on time-slicing. |
|
5. In addition, a given thread may, at any time, give up its right to execute by calling the yield() method. Threads can only yield the CPU to other threads of the same
priority--attempts to yield to a lower priority thread are ignored. |
|
| 6. When all the "Runnable" threads in the system have the same priority, the scheduler chooses the next thread to run in a simple, non-preemptive, round-robin scheduling order. |
|
|
| Daemon Threads |
| Daemon threads are those that provide a service for other threads in the system. Any Java thread can be a daemon thread. |
|
|
|
|
|
|
| Multithreading |
|
| Thread Group |
|
| All threads belong to a thread group. ThreadGroup, a java.lang class, defines and implements the capabilities of a group of related threads. |
|
| The ThreadGroup class manages groups of threads for Java applications. A ThreadGroup can contain any number of threads. The threads in a group are generally related in some way, such as who created them, what function they perform, or when they should be started and stopped. |
|
| ThreadGroups can contain not only threads but also other ThreadGroups. The top most thread group in a Java application is the thread group named "main". We can create threads and thread groups in the "main" group. We can also create threads and thread groups in subgroups of "main" and so on. |
|
| The result is a root-like hierarchy of threads and thread groups. |
|
|
|
|
| The ThreadGroup class has methods that can be categorized as follows: |
|
| 1. Collection management Method:-methods that manage the collection of threads and subgroups contained in the thread group. |
|
| 2. Method that Operate on the Group:-these methods set or get attributes of the ThreadGroup object. |
|
| 3. Method that Operate on All Threads within a Group --this is a set of methods that perform some operation, such as start or resume, on all the threads and subgroups within the ThreadGroup. |
|
| 4. Access Restriction Methods:-ThreadGroup and Thread allow the security manager to restrict access to threads based on group membership. |
|
|
| Collection Management Methods |
| The ThreadGroup provides a set of methods that manage the threads and subgroups within the group and allow other objects to query the ThreadGroup for information about its contents. |
|
| For example, |
| You can call ThreadGroup's activeCount() method to find out the number of active threads currently in the group. The activeCount() method is often used with the enumerate() method to get an array filled with references to all the active threads in a ThreadGroup. |
|
| For example, |
| The listCurrentThreads() method in the following example fills an array with all of the active threads in the current thread group and prints their names: |
|
class EnumerateTest
{
void listCurrentThreads()
{
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
int numThreads;
Thread[] listOfThreads;
numThreads = currentGroup.activeCount();
listOfThreads = new Thread[numThreads];
currentGroup.enumerate(listOfThreads);
for (int i = 0; i < numThreads; i++) {
System.out.println("Thread #" + i + " = " + listOfThreads[i].getName());
}
}
} |
|
|
| Other collection management methods provided by the ThreadGroup class include activeGroupCount() and list(). |
|
|
|
|
|
| Multithreading |
|
| Methods that Operate on the Group |
|
| The ThreadGroup class supports several attributes that are set and retrieved from the group as a whole. These attributes include the maximum priority that any thread within the group can have, whether the group is a "daemon" group, the name of the group, and the parent of the group. |
|
| The methods that get and set ThreadGroup attributes operate at the group level. That is, they inspect or change the attribute on the ThreadGroup object, but do not affect any of the threads within the group. |
|
|
| The following is a list of ThreadGroup methods that operate at the group level: |
| 1. getMaxPriority(), and setMaxPriority() |
| 2. getDaemon(), and setDaemon() |
| 3. getName() |
| 4. getParent(), and parentOf() |
| 5. toString() |
|
| So for example, when we use setMaxPriority() to change a group's maximum priority, we are only changing the attribute on the group object; we are not changing the priority of any of the threads within the group. |
|
|
| Consider this small program that creates a group and a thread within that group: |
|
class MaxPriorityTest
{
public static void main(String[] args)
{
ThreadGroup groupNORM = new ThreadGroup(
"A group with normal priority");
Thread priorityMAX = new Thread(groupNORM,
"A thread with maximum priority");
// set Thread's priority to max (10)
priorityMAX.setPriority(Thread.MAX_PRIORITY);
// set ThreadGroup's max priority to normal (5)
groupNORM.setMaxPriority(Thread.NORM_PRIORITY);
System.out.println("Group's maximum priority = " +
groupNORM.getMaxPriority());
System.out.println("Thread's priority = " +
priorityMAX.getPriority());
}
} |
|
When the ThreadGroup groupNORM is created, it inherits its maximum priority attribute from its parent thread group.
In this case, the parent group priority is the maximum (MAX_PRIORITY) allowed by the Java runtime system.
Next the program sets the priority of the priorityMAX thread to the maximum allowed by the Java runtime system. Then the program lowers the group's maximum to the normal priority (NORM_PRIORITY).
The setMaxPriority() method does not affect the priority of the priorityMAX thread, so that at this point, the priorityMAX thread has a priority of 10 which is greater than the maximum priority of its group groupNORM. This is the output from the program: |
Group's maximum priority = 5
Thread's priority = 10 |
|
|
| As we can see a thread can have a higher priority than the maximum allowed by its group as long as the thread's priority is set before the group's maximum priority is lowered. A thread group's maximum priority is used to limit a thread's priority when the thread is first created within a group or when you use setPriority() to change the thread's priority. Note that setMaxPriority() does change the maximum priority of all of its sub-threadgroups. |
|
|
|
| Methods that Operate on All Threads within a Group |
| The ThreadGroup class has three methods that allow us to modify the current state of all the threads within that group: |
| 1. resume() |
| 2. stop() |
| 3. suspend() |
|
| These methods apply the appropriate state change to every thread in the thread group and its subgroups. |
|
|
|
|
|
|
| Multithreading |
|
| Access Restriction Methods |
|
| The ThreadGroup class itself does not impose any access restrictions, such as allowing threads from one group to inspect or modify threads in a different group. Rather the Thread and ThreadGroup classes cooperate with security managers (subclasses of the java.lang.SecurityManager class), which can impose access restrictions based on thread group membership. |
|
| The Thread and ThreadGroup class both have a method, checkAccess(), which calls the current security manager's checkAccess() method. The security manager decides whether to allow the access based on the group membership of the threads involved. If access is not allowed, the checkAccess() method throws a SecurityException. Otherwise, checkAccess() simply returns. |
|
| The following is a list of ThreadGroup methods that call ThreadGroup's checkAccess() before performing the action of the method. These are what are known as regulated accesses, that is, accesses that must be approved by the security manager before they can be completed. |
| 1. ThreadGroup(ThreadGroup parent, String name) |
| 2. setDaemon(boolean isDaemon) |
| 3. setMaxPriority(int maxPriority) |
| 4. stop() |
| 5. suspend() |
| 6. resume() |
| 7. destroy() |
|
|
|
| This is a list of the methods in the Thread class that call checkAccess() before proceeding: |
| 1. constructors that specify a thread group |
| 2. stop() |
| 3. suspend() |
| 4. resume() |
| 5. setPriority(int priority) |
| 6. setName(String name) |
| 7. setDaemon(boolean isDaemon) |
|
| We can define and implement our own access restrictions for thread groups by subclassing SecurityManager, overriding the appropriate methods, and installing it as the current security manager in our application. |
|
|
|
|
|
|
| Multithreading |
|
| The notifyAll() and wait() Methods |
|
| The notifyAll() and wait() methods can be invoked only by the thread that holds the lock. |
|
|
| The notifyAll() method |
| The notifyAll() method notifies all the threads waiting on the monitor held by the current thread and wakes them up. |
| Example: |
public synchronized int get()
{
while (available == false)
{
try
{
wait();
}
catch (InterruptedException e)
{
}
}
available = false;
notifyAll(); // notifies Producer
return contents;
} |
|
| In the above example the Producer/Consumer example, the Consumer thread calls the get() method, so the Consumer thread holds the monitor during the execution of get(). At the end of the get() method, the call to notifyAll() wakes up the Producer thread that is waiting to get the monitor. Now, the Producer thread can get the monitor and proceed. |
|
| If multiple threads are waiting for a monitor, the Java runtime system chooses one of the waiting threads to run, making no commitments or guarantees about which thread will be chosen. |
|
|
| The wait() method |
| The wait() method causes the current thread to wait (possibly forever) until another thread notifies it of a condition change. |
| We use wait() in conjunction with notify() or notifyAll() to coordinate the activities of multiple threads using the same resources. |
|
| Example: |
public synchronized int get()
{
while (available == false)
{
try
{
wait(); // waits for notifyAll() call from Producer
} catch (InterruptedException e)
{
}
}
available = false;
notifyAll();
return contents;
} |
|
| The Object class contains two other versions of the wait() method: |
| wait(long timeout) |
|
| waits for notification or until the timeout period has elapsed--timeout is measured in milliseconds. |
| wait(long timeout, int nanos) |
|
| waits for notification or until timeout milliseconds plus nanos nanoseconds have elapsed. |
|
| It has a number of methods, some of which are static. |
|
|
|
|
|
|
| Multithreading |
|
| Frequently used Method |
|
| The most frequently used methods are the following: |
|
|
|
|
|
|
|
|
| Exception Handling |
|
| Introduction |
|
| Errors are a normal part of programming. |
|
| Some of these errors are flaws in a program's basic design or implementation--these are called bugs. |
|
| Other types of errors are not really bugs; rather, they are the result of situations like low memory or invalid filenames. |
|
| The way we handle the second type of error determines whether they become bugs. |
|
| Java's exception-handling mechanism lets us handle errors without forcing us to spend most of our energy worrying about them. |
|
|
|
|
|
|
| Exception Handling |
|
| What Is an Exception? |
|
| As the name implies, an exception is an exceptional condition. An exception is something out of the ordinary. Most often, exceptions are used as a way to report error conditions. |
|
| Exceptions provide notification of errors and a way to handle them. This control structure allows us to specify exactly where to handle specific types of errors. |
|
|
|
|
|
|
|
|
|
|
| Exception Handling |
|
| If Exceptions than? |
|
| The most common means of error checking is the function's return value. |
| Consider the problem of calculating the retail cost of an item and displaying it. For this example, the retail cost is twice the wholesale cost: |
|
int retailCost( int wholesale )
{
if ( wholesale <= 0 )
{
return 0 ;
}
return (wholesale * 2 ) ;
} |
|
| The retailCost() method takes the wholesale price of an item and doubles it. If the wholesale price is negative or zero, the function returns zero to indicate that an error has occurred. |
|
|
|
| Exception Handling |
|
| The exception handling technique |
|
| • Involves the use of the try, catch, and finally Java keywords |
| • Consists of several steps |
|
|
| 1. try a block of code that may result in an exception being "thrown" |
|
| 2. Code one or more blocks designed to automatically catch and handle a specific type of exception if one occurs. At most, only one of these blocks can be called in a single pass through the code. If none of the specified exceptions occurs, none of the blocks will be executed. |
|
| 3. Optionally code a block that will finally be run in ALL situations, whether an exception occurs or not |
|
|
| • Has the following general syntax: |
|
try
{
statements that may result in an exception being thrown;
}
catch (exception-type1 reference)
{
statements to handle the exception;
}
catch (exception-type2 reference)
{
statements to handle the exception;
}
other catch blocks...
finally
{
statements to be ALWAYS executed;
} |
|
| Example: |
| The following is a modified version of the "shell game" program presented earlier. It contains a try block and two catch blocks. One handles a NullPointerException and the other handles an ArrayIndexOutOfBoundsException. No finally block is specified, so logic comes together after the end of the last catch block. |
|
public class AppExcep
{
public static void main(String[] args)
{
// Loop control variable.
char again = 'y';
// Main loop. One array is entered and processed in each iteration.
while (again == 'Y' || again =='y')
{
// Instantiate a three element array and load a single String
// at a random element location.
String[] strings = new String[3];
int randomIndex = (int) ((Math.random()*100) % strings.length);
strings[randomIndex] = "Lucky";
// Ask the user to guess the element location.
Utility.separator(50, '>');
System.out.print("Pick a number from 1 to " + strings.length + ": ");
// "Try" to read their response, use it to index into the array,
// and see if they win.
try
{
// If they guess the element location, display a message. Otherwise,
// an exception will occur.
if (strings[Keyboard.readInt() - 1].equals("Lucky"))
{
Utility.skip();
System.out.println(" YOU WIN!!!");
}
}
// This block is automatically executed if a NullPointerException
// occurs to indicate a null array location.
catch (NullPointerException err)
{
Utility.skip();
System.out.println(" Empty shell - YOU LOSE!!!");
}
// If an ArrayIndexOutOfBoundsException occurs, this block is
// automatically executed. It indicates an invalid number was
// used as an index.
catch (ArrayIndexOutOfBoundsException err)
{
Utility.skip();
System.out.println(" Invalid number - YOU LOSE");
}
// Ask the user if they want to do it again and repeat the loop as
// requested.
Utility.separator(40, '=');
System.out.print("Again? (Y/N): ");
again = Keyboard.readChar();
}
}
} |
|
|
|
|
|
|
| Exception Handling |
|
| Some Terminology |
|
| Exception handling can be viewed as a nonlocal control structure. |
| When a method throws an exception, its caller must determine whether it can catch the exception. |
| If the calling method can catch the exception, it takes over and execution continues in the caller. |
|
| Java exceptions are class objects subclassed from java.lang.Throwable. Because exceptions are class objects, they can contain both data and methods. In fact, the base class Throwable implements a method that returns a String describing the error that caused the exception. This is useful for debugging and if we want to give users a meaningful error message. |
|
|
|
|
|
|
| Exception Handling |
|
| Throw an Exception |
|
| The method instantiates an object of type Exception. The Exception constructor takes a String parameter. The string contains a message that can be retrieved when the exception is caught. |
|
| The throw statement terminates the method and gives its caller the opportunity to catch it: |
|
if( correct > total )
{
throw new Exception( "Invalid values" ) ;
}
if ( (float)correct / (float)total > 0.70 )
{
returnCode = true ;
}
return returnCode ;
} |
|
|
|
| Exception Handling |
|
| Throw, try, and catch Blocks |
|
| To respond to an exception, the call to the method that produces it must be placed within a try block. |
|
| A try block is a block of code beginning with the try keyword followed by a left and right curly brace. Every try block is associated with one or more catch blocks. Here is a try block: |
|
try
{
// method calls go here
} |
|
| If a method is to catch exceptions thrown by the methods it calls, the calls must be placed within a try block. |
|
| If an exception is thrown, it is handled in a catch block. Different catch blocks handle different types of exceptions. |
|
| This is a try block and a catch block set up to handle exceptions of type Exception: |
|
try
{
// method calls go here
}
catch( Exception e )
{
// handle exceptons here
} |
|
| When any method in the try block throws any type of exception, execution of the try block ceases. Program control passes immediately to the associated catch block. |
| If the catch block can handle the given exception type, it takes over. |
|
| If it cannot handle the exception, the exception is passed to the method's caller. In an application, this process goes on until a catch block catches the exception or the exception reaches the main() method uncaught and causes the application to terminate. |
|
|
| An Exceptional Example |
| The gradeTest application. |
|
import java.io.* ;
import java.lang.Exception ;
public class gradeTest
{
public static void main( String[] args )
{
try
{
// the second call to passingGrade throws
// an excption so the third call never
// gets executed
System.out.println( passingGrade( 60, 80 ) ) ;
System.out.println( passingGrade( 75, 0 ) ) ;
System.out.println( passingGrade( 90, 100 ) ) ;
}
catch( Exception e )
{
System.out.println( "Caught exception --" +
e.getMessage() ) ;
}
}
static boolean passingGrade( int correct, int total )
throws Exception
{
boolean returnCode = false ;
if( correct > total ) {
throw new Exception( "Invalid values" ) ;
}
if ( (float)correct / (float)total > 0.70 )
{
returnCode = true ;
}
return returnCode ;
}
} |
|
|
|
| The second call to passingGrade() fails in this case because the method checks to see whether the number of correct responses is less than the total responses. |
|
|
| When passingGrade() throws an exception, control passes to the main() method. In the example, the catch block in main() catches the exception and prints Caught exception - Invalid values. |
|
|
|
|
|
| Exception Handling |
|
| Multiple catch Blocks |
|
| In some cases, a method may have to catch different types of exceptions. Java supports multiple catch blocks. Each catch block must specify a different type of exception: |
|
try
{
// method calls go here
}
catch( SomeExceptionClass e )
{
// handle SomeExceptionClass exceptions here
}
catch( SomeOtherExceptionClass e )
{
// handle SomeOtherExceptionClass exceptions here
} |
|
| When an exception is thrown in the try block, it is caught by the first catch block of the appropriate type. |
| A method that ignores exceptions thrown by the method it calls. |
|
import java.io.* ;
import java.lang.Exception ;
public class MultiThrow
{
public static void main( String[] args )
{
try
{
fool() ;
}
catch( Exception e )
{
System.out.println( "Caught exception " +
e.getMessage() ) ;
}
}
static void fool() throws Exception
{
bar() ;
}
static void bar() throws Exception
{
throw new Exception( "Who cares" ) ;
}
} |
|
|
|
| In the example main() calls fool() which calls bar(). Because bar() throws an exception and doesn't catch it, fool() has the opportunity to catch it. The fool() method has no catch block, so it cannot catch the exception. In this case, the exception propagates up the call stack to fool()'s caller, main(). |
|
| A method that catches and rethrows an exception. |
|
import java.io.* ;
import java.lang.Exception ;
public class MultiThrowA
{
public static void main( String[] args )
{
try
{
fool() ;
}
catch( Exception e )
{
System.out.println( "Caught exception " +
e.getMessage() ) ;
}
} static void fool() throws Exception
{
try
{
bar() ;
}
catch( Exception e )
{
System.out.println( "Re throw exception -- " +
e.getMessage() ) ;
throw e ;
}
}
static void bar() throws Exception
{
throw new Exception( "Who cares" ) ;
}
} |
|
|
|
| The fool() method calls bar(). The bar() method throws an exception and fool() catches it. In the example, fool() simply rethrows the exception, which is ultimately caught in the application's main() method. In a real application, fool() could do some processing and then rethrow the exception. This arrangement allows both fool() and main() to handle the exception. |
|
|
|
|
|
|
| Exception Handling |
|
| The finally Clause |
|
| Java introduces a new concept in exception handling: the finally clause. The finally clause sets apart a block of code that is always executed. |
|
| Example of a finally clause: |
|
import java.io.* ;
import java.lang.Exception ;
public class MultiThrowFin
{
public static void main( String[] args )
{
try
{
alpha() ;
}
catch( Exception e )}
{
System.out.println( "Caught exception " ) ;
}
finally()
{
System.out.println( "Finally. " ) ;
}
}
} |
|
| In normal execution (that is, when no exceptions are thrown), the finally block is executed immediately after the try block. |
| When an exception is thrown, the finally block is executed before control passes to the caller. |
| If alpha() throws an exception, it is caught in the catch block and then the finally block is executed. |
| If alpha() does not throw an exception, the finally block is executed after the try block. If any code in a try block is executed, the finally block is executed as well. |
|
|
|
|
|
|
| Exception Handling |
|
| The Throwable Class |
|
| All exceptions in Java are subclassed from the class Throwable. |
|
| If we want to create your own exception classes, we must subclass Throwable. Most Java programs do not have to subclass their own exception classes. |
|
| Following is the public portion of the class definition of Throwable: |
|
public class Throwable
{
public Throwable() ;
public Throwable(String message) ;
public String getMessage()
public String toString() ;
public void printStackTrace() ;
public void printStackTrace(
java.io.PrintStream s) ;
private native void printStackTrace0(
java.io.PrintStream s);
public native Throwable fillInStackTrace();
} |
|
| Java exceptions are Throwable objects (they are instances of Throwable or a subclass of Throwable). The Java packages contain numerous classes that derive from Throwable and thus, build a hierarchy of Throwable classes. |
|
|
|
|
|
|
|
|
|
| Exception Handling |
|
| Types of Exceptions |
|
| The methods of the Java API and the language itself also throw exceptions. |
|
| These exceptions can be divided into two classes: Exception and Error. |
|
| Both the Exception and Error classes are derived from Throwable. |
| Exception and its subclasses are used to indicate conditions that may be recoverable. Error and its subclasses indicate conditions that are generally not recoverable and that should cause your applet to terminate. |
|
| The various packages included in the Java Development Kit throw different kinds of Exception and Error exceptions, as described in the following sections. |
|
|
|
|
|
|
|
| Exception Handling |
|
| Different List of Exception |
|
| java.awt Exceptions |
| The AWT classes have members that throw one error and two exceptions: |
| • AWTException (exception in AWT) |
| • llegalComponentStateException (a component is not in the proper state for a requested operation) |
| • AWTErr (error in AWT) |
|
|
| java.awt.datatransfer Exception |
| Classes of the AWT data transfer package may throw this exception: |
| • UnsupportedFlavorException (data in improper format) |
|
|
| java.beans Exceptions |
| The classes of the java.beans package throw the following exceptions: |
| • IntrospectionException (unable to resolve object during introspection) |
| • PropertyVetoException (illegal property change) |
|
|
| java.io Exceptions |
| The classes in the java.io package throw a variety of exceptions, Any classes that work with I/O are good candidates to throw recoverable exceptions. For example, activities such as opening files or writing to files are likely to fail from time to time. The classes of the java.io package do not throw errors at all. |
|
|
| The java.io exceptions. |
|
|
|
|
|
|
|
| The java.io exception hierarchy. |
|
|
| java.lang Exceptions |
| The java.lang package contains much of the core Java language. The exceptions subclassed from RuntimeException do not have to be declared in a method's throws clause. These exceptions are considered normal because nearly any method can throw them. |
|
|
| The java.lang exceptions. |
|
|
|
|
|
| The java.lang errors. |
|
|
|
|
|
|
| The java.lang exception hierarchy. |
|
|
|
| java.lang.reflect Exception |
| The classes of java.lang.reflect throw the following exception: |
| • InvocationTargetException (invoked method has thrown an exception) |
|
|
| java.net Exceptions |
| The java.net package handles network communications. Its classes most often throw exceptions to indicate connect failures and the like. |
|
|
| The java.net exceptions. |
|
|
|
|
|
|
| The java.net exception hierarchy. |
|
|
| java.rmi Error |
| The Java Remote Method Invocation classes allow Java objects to exist on remote machines. These classes throw the following error: |
| • ServerError (remote server indicates error) |
|
|
| java.rmi Exceptions |
| Java objects whose methods are invoked remotely through RMI may throw exceptions. |
|
|
| The java.rmi exceptions. |
|
|
|
|
|
|
|
| The java.rmi exception hierarchy. |
|
|
| java.rmi.server Exceptions |
| RMI servers throw exceptions. |
|
|
| The java.rmi.server exceptions. |
|
|
|
|
|
| java.security Exceptions |
| The Java security API allows users to implement security features in Java. The API includes support for digital signatures, data encryption, key management, and access control. |
|
|
| The java.security exceptions. |
|
|
|
|
|
|
| The java.security exception hierarchy. |
|
|
| java.security.acl Exceptions |
| The Java security access control list API allows Java developers to control access to specific users. The classes of java.security.acl throw the following exceptions: |
| • ACLNotFoundException (unable to find access control list) |
| • LastOwnerExcepti (attempt to delete last owner of ACL) |
| • NotOwnerExcepti (only the owner may modify) |
|
|
| java.sql Exceptions |
| The Java SQL API throws the following exceptions: |
| • DataTruncation (unexpected data truncation) |
| • SQLException (SQL error--contains detailed SQL information) |
| • SQLWarning (SQL warning) |
|
|
| java.text Exception |
| The Java text API throws the following exception: |
| • FormatException (format or parsing error) |
|
|
| java.util Exceptions |
| The classes of the java.util package throw the following exceptions: |
| • EmptyStackException (no objects on stack) |
| • MissingResourceException (resource missing) |
| • NoSuchElementException (no more objects in collection) |
| • TooManyListenersException (thrown by unicast event listeners) |
|
| NOTE: |
| Unicast is Java terminology for a singleton server object. Singletons are objects that can be instantiated only once. |
|
|
| java.utils.zip Exceptions |
| The Java utilities zip API throws the following exceptions: |
| • DataFormatException (format error) |
| • ZipException (Zip error) |
|
|
|
|
|
|
| Exception Handling |
|
| Built-In Exceptions |
|
| Here application creates a method and forces it to divide by zero. The method does not have to explicitly throw an exception because the division operator throws an exception when required. |
|
| An example of a built-in exception. |
|
import java.io.* ;
import java.lang.Exception ;
public class DivideBy0
{
public static void main( String[] args )
{
int a = 2 ;
int b = 3 ;
int c = 5 ;
int d = 0 ;
int e = 1 ;
int f = 3 ;
try
{
System.out.println( a+"/"+b+" = "+div( a, b ) ) ;
System.out.println( c+"/"+d+" = "+div( c, d ) ) ;
System.out.println( e+"/"+f+" = "+div( e, f ) ) ;
}
catch( Exception except )
{
System.out.println( "Caught exception " +
except.getMessage() ) ;
}
}
static int div( int a, int b ) {
return (a/b) ;
}
} |
|
|
|
| The output of this application is shown here: |
2/3 = 0
Caught exception / by zero |
|
| The first call to div() works fine. The second call fails because of the divide-by-zero error. Even though the application did not specify it, an exception was thrown--and caught. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0 comments: