Exceptions and Threads


Exceptions

What is exception handling

Exception handling in Java is done for error processing. If there is an error, your 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 let it be handled by someone else.

Exceptions are available in many different languages and are used in many different ways. Java follows C++'s 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 occurred 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)

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: What else is so great about exceptions?
A: Remember #ifdef DEBUG ...? Well exceptions can replace such code and error processing can be centralized regardless of platform. i.e under UNIX signal were a form of exceptions, but it's not portable to other OSes.

Q: javac keeps on giving me this warning "must be caught or thrown, blah, blah"?
A: A exception might occur there. You must either handle it there or rethrow the exception.

Q: What are the most common Exceptions?
A: NullPointerException, MalformedURLException, NumberFormatException, IOException..

Threads

What are threads?

Threads allow for multiple flows of execution within a process(i.e an application) simultaneously. They're a single logical execution path, a defined start and an end. If are interruptable, are pre-emptive. They share the same resources as other threads, unlike process which have their own copy of code and data(separate from other processes).

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"));
        }

import java.awt.*;
import java.applet.*;

public class ThreadedApplet extends Applet implements Runnable
{
	Button b1;
	int x = 0;
	boolean suspended = false;

	Thread one = null;

	// Two buttons, one with a number the other with "Stop"
	public void init()
	{
		add(b1 = new Button("000000"));
	}

        public void start()
        {
		// Create a new thread with minimum priority
		// "this" refers to the current class which is a Runnable
		if(one == null)
		{
			x = 0;
                	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 
			{ 
				one.sleep(1000); 
			}
			catch(InterruptedException e) {}
                }
        }

	public boolean mouseDown(Event evt, int x, int y)
	{
        	if (suspended) 
		{
            		one.resume();
        	}
        	else 
		{
            		one.suspend();
        	}
        	suspended = !suspended;

		return true;
	}
                 
        public void stop()
        {
                // kill thread
                one = null;
        }

}


To view this applet you'll need a Java-enabled browser

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
  1. Implements Runnable
  2. 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.

  1. Thread()
  2. Thread(Runnable)
  3. Thread(ThreadGroup, Runnable)
  4. Thread(String name)
  5. Thread(ThreadGroup)
  6. Thread(Runnable, String name)
  7. 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. 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

[Q & A's]

Q: Difference between using Interface vs. sub-class of Thread for Threading?
A: With the interface, you do not need to create another class w/ a run() method. Rather have the run() method in the class that implements the Runnable interface. run() is called when the tread begins execution. In the case of a sub-class of Thread. It's run() method is called. In both cases you create almost in the same manner.
Q: Why do you have an infinite loop in run()?
A: We loop infinitely until the thread gets interrupted. If the thread never does, then the thread will hog all of the CPU cycles

Q: Why do you call sleep()?
A: To 'delay'(or put asleep) the thread for a few milliseconds(i.e 1000 = 1 sec).
Q: How many threads can you create?

A: As many as the system you are using allows. There isn't a limit, but there have been reported cases where the system or program crashes due to a large number of threads.

Q: Is there more information on threading?
A: Yes. Sun's programmer's guides are a good reference for Java-style threads


[Next] [Prev] [Home]
Nelson Yu
nelson@cs.ualberta.ca
Last modified: Jan 7 1996