Exceptions and Threads
Exceptions
What is exception handling
Exception handling in Java is done for error processing. If there is an
error, you application does not die a horrible death and dump core(in case of
DOS, crash). A exception is 'thrown' and you may 'catch' it to handle the error.
More importantly you separate real code from error processing, since you
can easily handle the error somewhere else or by someone else.
Exceptions are available in many different languages and are used in many
different ways. Java follows C++ exception handling closely, but leaves
many (unnecessary) parts out.
Throwing exceptions
When an error has occured you may throw an exception to signal an error
and handle the exception in a catch statement. But first we focus on throwing
exceptions.
In Java you must define what each method can throw, whereas in C++ this is not
the case.
void MethodThatDies() throws NullPointerException, KitchenSinkException
You can also define your own exceptions instead of the ones pre-defined
by extending the Exception class and providing some extra functionality.
Catching exceptions
Figuring out which exception was thrown is done in the try/catch and
try/finally blocks. Java implements exception much like C++ does and thus if
you've used them before or in any other language they should be straight
forward(i.e OnError in BASICs is a form of exception handling)
int value;
try
{
for(x=0, value = 100;x < 100; x++)
{
value = value / x;
}
}
catch(ArithmeticException e)
{
System.out.println("Foolish mathematics")
}
catch(Exception e)
{
System.out.println("An error has occurred - scream for your life");
}
try/finally catches all exceptions.
What you should do in your exceptions
You should clean up the resources that were being used before the exception
if necessary. This is only necessary if you had initialize many threads,
windows, frames, etc that no longer need to be there. Generally most exceptions
should display an error to the user and warning him about what could happen
if he/she decides to continue.
public class ErrorDialog extends Dialog
{
ErrorDialog(Frame parent)
{
super(parent, true);
setLayout(new BorderLayout());
// A panel with Contine and Exit buttons
Panel p = new Panel();
p.add(new Button("Continue?"));
p.add(new Button("Exit"));
add("Center", new Label("An error has occurred. Continue?"))
add("South", p);
}
public boolean action(Event evt, Object arg)
{
if("Exit".equals(arg))
{
dispose();
System.exit(1);
}
return false;
}
}
..
// somewhere in a class
try
{
// Dangerous stuff here
}
catch(SomeException e)
{
ErrorWindow = new ErroDialog(this);
ErrorWindow.show();
}
There is no reason why in your catch block why you would not rethrow the exception
if you didn't want to handle it.
Where should you use them?
Place the try/catch blocks over code you are uncertain about or some
code that has been buggy and behaving unpredicatibly.
Good places for exception handling to be(and sometimes they are
required)
- File I/O
- Using Java Sockets, URLConnections, etc.
- When "new"ing objects
In fact when using classes such as FileInputStream, you must catch or rethrow
exceptions before the compiler lets your code to be compiled.
[Q & A's]
Q: ?
A:
Threads
What are threads?
Threads allow for multiple flows of execution within a process(i.e an
application) simultaneously. They are a single logical execution path, a defined start and an end, that
if interruptable are pre-emptive threads. They share the same resources, unlike process which have
their own copy of code and data.
Graphically threads look like this:
import java.awt.*;
import java.applet.*;
public class ThreadedApplet extends Applet implements Runnable
{
Button b1;
int x = 0;
Thread one = null;
// Two buttons, one with a number the other with "Stop"
public void init()
{
add(b1 = new Button("000000"));
add("South", new Button("Stop"));
}
public void start()
{
// Create a new thread with minimum priority
// "this" refers to the current class which is a Runnable
if(one == null)
{
one = new Thread(this);
one.setPriority(Thread.MIN_PRIORITY);
one.start();
}
}
// Called when the Thread is created
public void run()
{
while(true)
{
b1.setLabel(new Integer(x++).toString());
try { Thread.sleep(1000); }
catch(InterruptedException e) {}
}
}
public boolean action(Event evt, Object arg)
{
if("Stop".equals(arg))
{
one = null;
return true;
}
return false;
}
public void stop()
{
// kill thread
one = null;
}
}
Benefits of threading over fork()
fork()ing under UNIX creates a child process which has its own copy of
the data and code of the parent. This is fine if you have plenty of
memory and CPU power and keep the number of child processes down to a
handful. More importantly, Java applets can not just 'spawn' any old process on
the clients end, since that is insecure and therefore disallowed.
Applications as well as Applets must use threading in certain circumstances.
For example, if you wanted a way to draw two images simultaneously, creating
another process is rather a back hack, same goes for a application which wants
to handle user input while printing or displaying a complex piece of graphics.
Pre-emptive multi-threading has its problems. One thread can interrupt
another at any given time, thus the moniker 'pre-emptive'. What if one
thread was writing to a array, while the other interrupted that thread
and started to write to the same array?
Languages like C and C++ need to lock() and unlock() data before and after
reading/writing to it. Java does away with this, it hides it the locking
of data via the 'synchronized' keyword.
i.e
synchronized int MyMethod();
Another areas that threads have proven to be useful is in GUIs.
There will be increased responsiveness when the computer is locked in some
lengthy calculation or operation and can not handle any user input, with the
use of threads.
Thus things can be done in the background or multiple things in the foreground(i.e play sound and
animations) without 'slowing' or giving the apperance of sluggish performance.
Ways of threading
There are essentially two main ways to achieve threading in Java. One is
to implement the Runnable interface, the other is to extend the Thread
class.
Two ways to get threading in your applet/application
- Implements Runnable
- Extend Thread
class MyThreads extends Threads
{
public void run()
{
}
}
class MyThreadedButton extends Button implements Runnable
{
public Button()
{
new Thread(this);
}
public void run()
{
/// Gets executed when the Thread is created
}
}
You'll need to create an instance of Thread before threading can occur. Thus
if your class implemented the interface runnable you could use methods 1,2,4,5.
and pass "this" when a Runnable is required.
- Thread()
- Thread(Runnable)
- Thread(ThreadGroup, Runnable)
- Thread(String name)
- Thread(ThreadGroup)
- Thread(Runnable, String name)
- Thread(ThreadGroup, Runnable, String name)
The thread stops executing when run() returns(i.e is finished) or stop() is
called. Well-behaved apps and applets do not hog the CPU and yield to other
threads and process. So it stop(), clean up your resources and kill the
thread.
Priorities
A thread's priority can be set with setPriority(int) where the parameter is
one of the following.
- MAX_PRIORITY
- MIN_PRIORITY
- NORM_PRIORITY
I'd be warying of changing a threads priority like you'd change the background
of a container.
Well-behaved multi-threading
Well-behaved multi-threading
- Use the synchronized keyword for data and functions that will
be accessed by multiple threads.
- Remember to clean up resources properly and kill active threads in stop().
- Remember to handle user input, if they want a threaded animation stopped
- Avoid sucking up too much CPU time by creating too many useless threads or
demanding a high priority for a low-priority activity.
[Q & A's]
Q: ?
A:
[Next]
[Prev]
[Home]
Nelson Yu
nelson@cs.ualberta.ca
Last modified: Dec 6 1995