Você está na página 1de 19

8966484.

doc FBE – Computer Science Dept

Mekelle University Faculty of Business & Economics

Computer Science Department

Comp 262: Internet Programming with Java

Handout 8 – Threads

Reference:
For more information on the material covered in this handout, you should take some
time to look at the Sun Java Tutorial, for which there is a link on the intranet, under
the materials listing for this course. See in particular the Threads topic, found in the
Essential Java Classes trail.

e-books on the Intranet – look for the section on applets in any of the Java books e.g.
• Teach Yourself Java in 21 Days (Books Macmillan)
• Java Developers Reference (Books Macmillan)
• Exploring Java (Books OReilly)

1 Overview
This handout introduces the concept of threading in programs. In Java, unlike other
languages such as C, threads have been built-in to the language so that it is easy for a
programmer to write a multi-threaded program.
However, the programmer should have a good understanding of threads and what it
means to create a multi-threaded program.

2 What is a thread?
A thread is a single sequential flow of control within a program – or a single thread of
execution within a program. A program can have multiple threads that are executing at
the same time.
Threading is used in programs to ensure that different tasks can execute
independently, without having to wait for other, non-related, tasks to complete. In
other words, threading allows you, the programmer, to make your programs do many
tasks at the same time.
This is similar to the way in which an operating system, such as Windows, can have
many different applications running at the same time – for example, you could start a
query in Access or SQL Server, and while it is running, switch to a Word document
and type text into it.

Some programs execute using a single thread – this is the case if a Java program is not
written to use multiple threads. If a program is written to use multiple threads, the
path of one thread through the program can be different from the paths of other
threads. For example, thread A might execute the if part of an if-else statement, while
another may execute the else part – this may be due to different inputs for each thread.

Consider a normal stand-alone Java program – to run the program, the interpreter
executes the main method of a class in the application.

Page 1 of 19
8966484.doc FBE – Computer Science Dept

This begins a thread for that program – the program is executed in the order defined
by the code. This order is predefined for a given set of inputs.
If threading is used in the program, the order of execution may be different for
different threads in the program.

In Java, support for multi-threading is built-in, through the java.lang.Thread class.


This is different to other programming languages, such as C and C++, for which you
would have to use external libraries to add threading.
To use multiple threads in a Java program, classes can inherit from the
java.lang.Thread class. Alternatively, a class can implement the java.lang.Runnable
interface.

3 A Simple Example – ThreadDemo


[Code Example: Threads/ThreadDemo.java]
Consider the following two simple classes (uses of the Thread class and its methods
are highlighted in bold):

// ThreadDemo.java

class ThreadDemo
{
public static void main (String [] args)
{
MyThread mt = new MyThread ();
mt.start ();

//for loop that prints out all the integers from 0 to 50, and
prints the square of each value
for (int i = 0; i < 10; i++)
System.out.println ("i = " + i + ", i * i = " + i * i);
}
}

class MyThread extends Thread


{
public void run ()
{
//for loop that prints a right-angled triangle composed of
asterisk (*) characters
for (int count = 1, row = 1; row < 20; row++, count++)
{
for (int i = 0; i < count; i++)
System.out.print ('*');

System.out.print ('\n');
}
}
}
Figure 1 – source code for ThreadDemo and MyThread classes
The ThreadDemo class creates an object of type MyThread. When the ThreadDemo
class is run (it has a main method), the first thing it does is to start a new thread that is
associated with the MyThread object. The program then outputs from the for loops in

Page 2 of 19
8966484.doc FBE – Computer Science Dept

both ThreadDemo and MyThread. But….the output lines of the two classes are mixed
together – it does not complete one before starting the other.
This is because there are two threads running – one to execute the main method of
ThreadDemo and one to execute the run method of MyThread.
Each thread runs independently of the other – each gets resources from the processor
as it needs them. The output from running ThreadDemo might look like that in Figure
2 below. In fact, each time the program is run, the order of the output may be different
– because it depends on when each thread gets the resources it needs.

Figure 2 – possible output when ThreadDemo is run


The two threads run within a single instance of the Java VM.
The Java VM is allocated resources by the operating system – the VM is a process
running on the PC or server. Each thread that runs within the VM can use the
resources allocated to the VM process by the operating system. In this way, a thread is
a bit like a process – in fact, a thread is sometimes referred to as a lightweight process.

4 Why and where to use threading?


Threading can be used in Java applications to avoid long delays between when a user
does something, e.g. entering input to a program and when the user sees something
happening in the program.
It can also be used to send some tasks, e.g. printing, to the background – where the
user does not have to wait for them to complete before moving on.

Threading can be used in stand-alone Java applications (run by the main method) and
can also be used in applets.

Page 3 of 19
8966484.doc FBE – Computer Science Dept

Applets often implement threading to avoid delays between things happening on the
screen – for example, in animations.
The event listener model for applets uses threads – when an event is detected (e.g. a
mouse click) the event is handled by a separate thread. If the handler needs to carry
out tasks that may take some time, the handler should hand off those tasks to another
thread – otherwise subsequent events requiring handling would have to wait for those
tasks to complete.

Multi-threaded programs can also take advantage of multiple processors. There are
many more multi-processor PCs available now than there used to be. If a program has
multiple threads, each thread can run on a separate processor. This is because a thread
has its own call stack (this is what the interpreter uses to keep track of what methods
have been called and in what order).
For example, a calculation that requires one hour on a single-processor machine
could, in theory, run in half an hour on a dual-processor machine or in 15 minutes on
a four-processor machine.

But a program does not have to be run on a multi-processor machine to take


advantage of threading – a Java program may simply need to carry out several tasks
simultaneously.

5 The Thread Class and the Runnable Interface

The example in section 3 above has a class MyThread that extends the
java.lang.Thread class. The diagram in Figure 3 below shows the class hierarchy –
MyThread inherits from the Thread class, which implements the Runnable interface.

java.lang.Thread implements
java.lang.Runnable
run()
run()
start()

extends

MyThread

run()

Figure 3 – class hierarchy showing the Java Thread class and Runnable interface

The Thread class has two methods that we have seen already (there are more, which
we will cover later) – a run and a start method. When the thread is started (by calling
the start() method), the run() method is executed. The run() method on the Thread
class does nothing – it is empty. A class that extends Thread usually overrides run()
with something that the class needs to do. Any Java statements can be used here.

Page 4 of 19
8966484.doc FBE – Computer Science Dept

For example, in the code examples, the SimpleThread class looks like this:

public 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((long)(Math.random() * 1000));
} catch (InterruptedException e) {}
}
System.out.println("BEKA! " + getName());
}
}
Figure 4 – source code for the SimpleThread class
When a thread is started for an object of this class, the run() method is executed. This
run method has a for loop that runs 10 times. Methods of the Thread class are
highlighted in bold. The sleep method causes the thread to stop for a specified time –
so this thread stops for a random time in between each loop iteration. The getName()
method is used to return the name of the thread. This is useful because each thread
that is started can be given a different name.
This thread can be started by instantiating an object from the class and invoking its
start method, like this:

public class TwoThreadsDemo {


public static void main (String[] args) {
new SimpleThread("Mekelle").start();
new SimpleThread("Addis").start();
}
}

Thread Method Description


sleep (long milliseconds_value) Causes the thread to stop for the specified number
of milliseconds. When sleep is called, an
InterruptedException must be caught:
public void run() {
……
try {
Thread.sleep(1000);
}
catch (InterruptedException e){ }
……
}
getName() Returns the name of the thread
start() Causes the run() method of the thread to begin
executing.

Page 5 of 19
8966484.doc FBE – Computer Science Dept

The Runnable interface also has the run() method – a class that implements Runnable
has to implement the run() method. A class that implements Runnable can run as a
thread.
If the class extends some other class, it can implement Runnable rather than extending
Thread. This is the case for an applet – an applet is always a sub-class of Applet or
JApplet, so if the applet needs to run as a thread, it should implement Runnable (see
the code example Clock.java).
The class can then be passed to the constructor for a Thread – because the Thread
constructor requires a parameter of type Runnable.

5.1 Thread Constructors


There are various different constructors for a Thread object. Some of these are shown
in the table below, along with some other methods of the class.

Thread Method Description


Thread(String name) Constructor – takes a name for the thread (see
SimpleThread example above – the super constructor is
called with this signature)
Thread(Runnable target, String name) Constructor – takes an object that is of type Runnable
(a class that implements Runnable) and a name for the
thread
Thread (Runnable target) Constructor - takes an object that is of type Runnable
(a class that implements Runnable)
setName(String name) Sets the name of the thread object

For example, the code example Clock.java is an applet that displays the time,
updating every second. The class implements Runnable. The start method of the
applet creates a new Thread object, using the constructor that takes a Runnable object
and a name as parameters. This is highlighted in bold in the extract from the code
shown below.

public class Clock extends java.applet.Applet implements Runnable {


private Thread clockThread = null;

public void init() {


setBackground(Color.white);
}

public void start() {


if (clockThread == null) {
clockThread = new Thread(this, "Clock");
clockThread.start();
}
}

Figure 5 – part of the source code for the Clock class


To summarise, the difference between extending the Thread class and implementing
the Runnable interface is this:
• A class that extends Thread is itself a thread and therefore it has all the thread-
management capabilities built-in to it (inherited from the Thread class)
• A class that implements Runnable must be managed by a separate Thread
object.

Page 6 of 19
8966484.doc FBE – Computer Science Dept

5.2 Stopping a Thread


In either case, the run() method is the body of the thread – it is what will be executed
when the thread is started. The thread runs until the run() method returns. This is the
case in the SimpleThread class, for which the source code is shown in Figure 4 above.
The run method of that class has a for loop that has 10 iterations, followed by a print
to the standard output:

for (int i = 0; i < 10; i++) {


System.out.println(i + " " + getName());
try {
sleep((long)(Math.random() * 1000));
} catch (InterruptedException e) {}
}
System.out.println("BEKA! " + getName());

Sometimes, the run() method has some kind of infinite loop running until the thread is
stopped by some external condition. This is often the case in an applet. For example,
in the Clock applet, the run() method repaints the applet every 1000 milliseconds. The
repaint is inside a while loop that checks the condition 'clockThread = = myThread'.
MyThread is the current thread under which the applet is running. The start() method
of the applet has already set the clockThread to be the applet itself, so the while
condition is always true while the applet is running.

The while condition will become false when the applet's stop() method is called
(when the browser leaves the web page) – because the stop() method sets the
clockThread reference to be null – so it is no longer the same as the current thread.

When the while loop finishes, there are no more statements in the run() method, so it
returns – thus stopping the thread. If the browser returns to the web page, the applet is
started again, resulting in a new thread starting up.

public void run() {

Thread myThread = Thread.currentThread();


while (clockThread == myThread) {
repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException e){ }
}
}
……
public void stop() {
clockThread = null;
}
Figure 6 – the thread run() method and the applet stop() method in the Clock applet
There is another way to stop a thread – by invoking its stop() method. But this is not
always safe, as it can stop a thread when it is in the middle of executing something,
leaving data in an inconsistent state.

Page 7 of 19
8966484.doc FBE – Computer Science Dept

The technique shown above – setting some flag and using that as an exit condition for
the run() method – is better because the thread is stopped at a natural point and there
is less, or no, risk of data being left in a bad state.

6 Thread Life-Cycle
6.1 Thread States
The diagram in Figure 7 below shows the life-cycle of a thread and the different
states a thread can be in during its lifetime. It shows also what methods can cause the
thread to change state. The different states are shown in bold boxes – New Thread,
Runnable, Not Runnable, Dead.

Thread is running…

start() sleep()

New Thread Runnable Not Runnable

run() method returns


Dead

Figure 7 – the life-cycle of a thread

When the thread object is created, it is in the New Thread state. For example:
clockThread = new Thread(this, "Clock");
The above line of code creates a new thread from the Clock applet class.

In this state, it is an empty thread for which no resources have yet been allocated. The
only method that can be called on the thread at this point is start().
The next line of code starts the thread:
clockThread.start();

The thread is now running – and it has entered the Runnable state. While the thread
is running, it can switch between two states – Runnable and Not Runnable. If the
sleep() method is called, the thread becomes Not Runnable.

When a Java program is running, there is an instance of the Java VM running as a


process under the operating system (OS). The OS allocates CPU resources to each
process it has running. The Java VM manages the distribution of those resources
among all the currently running threads – this is called scheduling. Java uses a very
simple scheduling algorithm called fixed priority scheduling to do this. So, a thread
that is running is not necessarily always doing something – it may be waiting to get
CPU resources.

When a thread is in the Not Runnable state, it does not run, even if processor
resources become available for it to use.

When the thread's run() method returns (due to a natural end or an exit condition
being fulfilled) or if the thread is stopped (by its stop() method – not recommended,
this is deprecated in newer versions of Java) the thread enters the Dead state.

Page 8 of 19
8966484.doc FBE – Computer Science Dept

The state of a thread can be checked with the isAlive() method of the Thread class.
This method returns true if the thread has been started and has not yet stopped – it is
in either the Runnable or Not Runnable states.
The method returns false if the thread is in the New Thread or Dead states.
It is not possible to determine if the thread is Runnable/Not Runnable or in the New
Thread/Dead states.

6.2 Setting Priorities


Any examples we have looked at so far where there were more than one thread
running have had the threads competing for the same resources. We have not allocated
any priority to tell the Java VM if a particular thread should get priority for resources.

The priority of a Thread object ranges from Thread.MIN_PRIORITY to


Thread.MAX_PRIORITY (constants in the Thread class). In most Java VMs, these are
set to 1 and 10, with 1 being the lowest priority.

When a thread is created, it inherits its priority from the thread that created it. If the
priority for a thread is not specified, it defaults to the constant value
Thread.NORM_PRIORITY, which is 5.

The priority of a thread can also be set using the setPriority() method. The value of
the priority can be accessed using getPriority().

When multiple threads are ready for execution, the VM chooses the runnable thread
that has the highest priority and executes it. Other, lower priority, threads will not be
executed until this thread stops or becomes unrunnable.

If two threads with equal priority are ready for execution, the scheduler chooses one
of them to run. The chosen one will run until it stops or becomes unrunnable, or until
a higher priority thread becomes runnable. The scheduler is preemptive – this means
that any time a thread with a higher priority becomes runnable, it will be chosen for
execution.

A thread can volunteer to give up processor resources to another thread of equal


priority, by calling the yield () method. If there are no runnable threads of equal
priority available, the yield is ignored.

Thread Method Description


setPriority(int newPriority) Sets the priority of the method to be the value
newPriority. Should use the Thread constant values,
not integer literals, as the range can be different on
different VMs. Examples:
setPriority (Thread.MAX_PRIORITY)
setPriority (this.getPriority() + 1)
setPriority (Thread.MIN_PRIORITY)
getPriority() Returns the priority of the thread object
yield() Allows other runnable threads of equal priority to run;
puts the thread into the Not Runnable state

Page 9 of 19
8966484.doc FBE – Computer Science Dept

6.3 Time-Slicing for Equal Priority Threads


However, we have seen when we run the ThreadDemo example that the first thread
that runs does not always complete before the second thread runs, even though the
priorities are the same. This is because some operating systems use a technique called
time-slicing to divide the time between threads that have equal priority. If the
operating system does this, a thread may stop executing because it is allocated a fixed
amount of time to use the resources. Resources are then handed to the other thread for
a fixed amount of time.

For example, if the priority of the second thread in the ThreadDemo class is set to the
maximum priority, it will always complete before the original thread executes. The
priority can be set by adding in the line shown in bold below:

MyThread mt = new MyThread ();


mt.start ();
mt.setPriority(Thread.MAX_PRIORITY);

On a system that does not do time-slicing, you can use the yield() method in threads
to make sure that one thread does not get all the resources until it completes.
Using yield makes a thread 'well-behaved'.

7 Synchronisation and Locking


[Code Example: Threads/ProducerConsumerTest.java]
We have already seen two ways of making a thread enter the Not Runnable state –
invoking the sleep() and yield() methods.
The Not Runnable state is sometimes also called the blocked state – because the
thread is blocked from running while in this state.

Another situation in which a thread may become Not Runnable is when it is waiting
for some other resource to be available, for example, data in a file or a database.
This often happens when a thread is sharing data with other threads and has to
consider what the other threads are doing with the data. In the same way that a DBMS
has to manage simultaneous data updates from different clients, a Java program may
need to handle simultaneous access to the same resource.

7.1 Producer-Consumer Scenario


One type of scenario where this happens is called a producer-consumer scenario. This
is where the producer generates some data which is consumed (used) by the
consumer. An example of this is where a producer thread is writing data to a file while
a consumer thread reads data from the same file. Or characters are typed on the
keyboard and a producer places the key events in queue to be read by a consumer.
In both these examples, the threads need to run concurrently (at the same time) and
share a common resource (the file or the queue).

If the access of each thread to the common resource is not synchronized in some way,
the consumer may not read all the data or key events from the file or queue.
A simple producer-consumer scenario is depicted in the diagram below. The two
threads are running concurrently, competing for the same resources.

Page 10 of 19
8966484.doc FBE – Computer Science Dept

• Time is shown on the left axis.


• The Producer Thread puts items into a common resource – let us call it ‘the
box’.
• Each time the Producer puts a new item into the box, it replaces the previous
item.
• The Consumer Thread reads items from the box.
• The Consumer should read all the items that get put into the box.
• If the Consumer checks the box while the Producer is in the process of putting
Item2 into the box, it will get Item1.
• If the Consumer next checks the box after Item3 has been put into it, it will get
Item3. So the Consumer does not get Item2 (so, if this was a queue of key
events, the Consumer would miss one of the key presses).

Time

Common resource – the box


Producer thread Consumer thread

Put Item1
Get item

Put Item2
Get item
Put Item3

Figure 8 – Producer-Consumer scenario – concurrently running threads

In order to ensure that the Consumer gets all the items, in the correct sequence, the
access to the box by both threads must be synchronised – they must be timed in such a
way that the Producer waits for the Consumer to get the last item before it puts in a
new item. The sequence should be something like this:

Producer: Put Item1


Consumer: Get Item1 (notify Producer when it has got it)
Producer: Put Item2
Consumer: Get Item2 (notify Producer when it has got it)

We can extend this further to say that the Consumer should not attempt to get an item
unless it knows the Producer has finished putting it in. So the Producer needs to also
notify the Consumer:

Producer: Put Item1 (notify Consumer when ready)


Consumer: Get Item1 (notify Producer when it has got it)
Producer: Put Item2 (notify Consumer when ready)
Consumer: Get Item2 (notify Producer when it has got it)

Page 11 of 19
8966484.doc FBE – Computer Science Dept

The main ideas here are that the Producer and the Consumer threads cannot be
simultaneously accessing the box and that each one must tell the other when it has
completed its action.
Each thread has to get a lock on the box when it accesses it – while the lock is in
place, the other thread cannot access the box. Each thread also has to notify the other
when the item is available (Producer to Consumer) or has been taken (Consumer to
Producer).

7.2 Synchronized Access – Locking Objects


The way to do this in Java is to make the parts of code that involve access to the
common resource by synchronized. These parts of the code are called the critical
sections of the program. A block of code or a method can be declared synchronized.
Java associated a lock with every object (instance of the class) that has synchronized
code in it.

At runtime, whenever control enters the synchronized block or method, the thread that
is calling it locks the object whose code block or method is being called.
When an object is locked, no other threads can call any synchronized code on the
object (other threads can call non-synchronized blocks/methods of the object).
When control passes from the synchronized block or method, the lock is released – so
other threads can call the code.

The Java interpreter automatically locks and releases locks in this way.

7.3 Wait and Notify


In addition to locking the box object, the Producer and Consumer threads need to
notify each other when they have completed their actions of putting and getting items.
Each thread needs to know when the other has notified it of completion.
The Producer needs to check if the Consumer has taken the last item. If it has not been
taken, the Producer needs to wait for the Consumer to do so.
Likewise, the Consumer needs to check if the Producer has put a new item in the box.
If not, it needs to wait for the Producer to do so.

In Java, waiting and notifying can be carried out using the Object super class methods
wait() and notifyAll(). These methods, and some variations on them, are described in
the table below.

Object Method Description


wait() If there is a lock on the object, calling wait() causes the lock to be
released. This allows another thread to access the object’s synchronised
code.
The object then waits until it receives a notification that the lock has
been released again; then the object that caused wait() to be called
originally gets the lock again.
wait (long timeout) Similar to wait(), but does not wait longer than timeout milliseconds.
notifyAll() Wakes up all threads waiting to get a lock on the object. All waiting
threads then compete for the lock – only one will get it , the others go
back to waiting.
notify() Wakes up some one of the waiting threads.

Page 12 of 19
8966484.doc FBE – Computer Science Dept

The code for the Box class below shows how synchronized methods and the wait()
and notifyAll() methods are used together to make our Producer-Consumer scenario
work the way we want it to.
In this class, the item is an integer that is stored in the instance variable contents.
Note that it uses a boolean flag, available – this is true when an item has been put into
the box by the Producer but has not yet been taken by the Consumer. It is false when
the item has been taken but a new item has not yet been put in.
The Producer calls the put() method to put in an item, setting the available flag to true.
The Consumer calls the get() method to get an item, setting the available flag to false.
Both the put() and get() methods use a while loop that checks the available flag. In
this way, the Producer can wait for the Consumer to take the last item, and the
Consumer can wait for the Producer to put the next item.

class Box {
private int contents;
private boolean available = false;

public synchronized int get() {


while (available == false) {
try {
wait();
} catch (InterruptedException e) { }
}
available = false;
notifyAll();
return contents;
}

public synchronized void put(int value) {


while (available == true) {
try {
wait();
} catch (InterruptedException e) { }
}
contents = value;
available = true;
notifyAll();
}
}
Figure 9 – source code for the Box class – a common resource shared by two threads

The Producer and Consumer thread classes are shown below. The run method for each
thread calls the put() or get() method, as appropriate. The ProducerConsumerTest
class has a main method that creates a Producer and a Consumer and starts each
thread.

class Producer extends Thread {


private Box box;
private int number;

public Producer(Box b, int number) {


box = b;

Page 13 of 19
8966484.doc FBE – Computer Science Dept

this.number = number;
}

public void run() {


for (int i = 0; i < 10; i++) {
box.put(i);
System.out.println("Producer #" + this.number
+ " put: " + i);
try {
sleep((int)(Math.random() * 100));
} catch (InterruptedException e) { }
}
}
}

class Consumer extends Thread {


private Box box;
private int number;

public Consumer(Box b, int number) {


box = b;
this.number = number;
}

public void run() {


int value = 0;
for (int i = 0; i < 10; i++) {
value = box.get();
System.out.println("Consumer #" + this.number
+ " got: " + value);
}
}
}

class ProducerConsumerTest {
public static void main(String[] args) {
Box b = new Box();
Producer p1 = new Producer(b, 1);
Consumer c1 = new Consumer(b, 1);

p1.start();
c1.start();
}
}
Figure 10 – the Producer and Consumer thread classes and a class to test the scenario

8 Daemons
[Code Examples: Threads/DemoDaemon.java]
A Daemon is a special kind of thread. If a daemon thread is running as part of a
program, the program can terminate without waiting for the daemon to finish
whatever it is doing.
Normal (non-daemon) threads must complete before the program can terminate – this
means their run() methods must return.

Page 14 of 19
8966484.doc FBE – Computer Science Dept

Therefore, daemon threads are useful for running background tasks that should run
continuously while the program runs. For example, a thread that monitors the
availability of system resources can be left to run in the background and can just stop
whenever everything else in the program is complete.

To make a daemon thread, call the setDaemon() method – it takes one boolean
parameter – if it is true, the thread becomes a daemon.
This method throws an IllegalThreadStateException, so this exception needs to be
caught in the code.

For example, the class below is a daemon thread:

class DemoDaemonThread extends Thread


{
public DemoDaemonThread(String name)
{super (name);
setDaemon (true);
}

public void run()


{int counter = 0;
while (1==1) //infinite loop
{
System.out.println (getName() + " - " + counter);
counter++;
}
}
}

This class is normal thread (not a daemon):

class DemoThread extends Thread

{
public DemoThread(String name)
{
super(name);
}

public void run()


{
for (int i=0; i <= 20; i++)
{
System.out.println (getName() + ": on iteration " + i
+ " of loop.");
}
}
}

The following class has a main method that starts both threads. If both threads were
normal, non-daemon, threads, the program would go on indefinitely – because of the
infinite while loop in the run() method of the DemoDaemonThread class. But,
because it is a daemon, the program terminates when all other threads have
completed.

Page 15 of 19
8966484.doc FBE – Computer Science Dept

class DemoDaemon
{
public static void main (String[] args)
{
DemoDaemonThread dt = new DemoDaemonThread("Daemon Thread");
DemoThread nt = new DemoThread ("Normal Thread");

dt.start();
nt.start();
}

You can check if a given thread is a daemon using the isDaemon() method of Thread:

threadObject = new Thread(runnable_object);


threadObject.isDaemon();

9 Timers
[Code Examples: Threads/Reminder.java, ReminderBeep.java]

Writing your own threads in the ways discussed in this handout can be complex and
difficult if there are many tasks to be handled.
To make the life of a programmer a bit easier, Java 1.3 introduced the java.util.Timer
and java.util.TimerTask classes. These can be used to run repetitive tasks, such as
monitoring.

The TimerTask class implements the Runnable interface, so it must override the run()
method.
A Timer object can schedule one or more TimerTask objects to be executed one time
or a number of times by a background thread. The tasks can be scheduled to run at a
time or times in the future or after a specified delay period.

TimerTask is abstract, so you extend it to define the tasks that need to be carried out.

For example, when the Reminder class below is run, it displays the output:
About to schedule task.
Task scheduled.

Then, 5 seconds later, the scheduled task runs and outputs:


Time's up!

The uses of the Timer and TimerTask classes are highlighted in bold.
import java.util.Timer;
import java.util.TimerTask;

/**
* Simple demo that uses java.util.Timer to schedule a task to
execute
* once 5 seconds have passed.
*/

Page 16 of 19
8966484.doc FBE – Computer Science Dept

public class Reminder {


Timer timer;

public Reminder(int seconds) {


timer = new Timer();
timer.schedule(new RemindTask(), seconds*1000);
}

class RemindTask extends TimerTask {


public void run() {
System.out.println("Time's up!");
timer.cancel(); //Terminate the timer thread
}
}

public static void main(String args[]) {


System.out.println("About to schedule task.");
new Reminder(5);
System.out.println("Task scheduled.");
}
}

Each task that you want the timer to run must be defined in a sub class of TimerTask.
The run() method defines what the task does.

A Timer object is instantiated and each task is scheduled using one of the schedule
methods (see the table below for the different versions). One Timer can schedule
multiple tasks – but all the tasks run as part of the same thread.
The program will keep running as long as any Timer threads are running, so the Timer
thread(s) must be stopped somehow. One way to do this is to call the cancel() method
of the Timer object, as is done in the RemindTask above:
timer.cancel();

If this call were not made, the program would keep running because there is a live
thread running (the Timer object).
Alternatively, the Timer object can be created as a daemon thread. The Timer has a
constructor that takes one boolean parameter – if it is true, the Timer object will be a
deamon thread. For example:

timer = new Timer(true);

However, for this example, the main method finishes after the line

System.out.println("Task scheduled.");

At this point, the program has finished executing; it has a thread (the Timer) but the
thread is a daemon, so the program terminates before the 5 seconds have elapsed for
the RemindTask to run.

However, there could be other threads running that stop the program from
terminating, even if the Timer thread is cancelled. If any of the AWT classes are used,
AWT automatically creates a non-daemon thread that keeps the program alive.

Page 17 of 19
8966484.doc FBE – Computer Science Dept

In this case, another way to tell the program to end all running threads and terminate
is to call System.exit(0).
See the code example ReminderBeep.java for an example of this (it uses the
java.awt.Toolkit class to make a beep sound in the TimerTask object).

The different schedule methods of the Timer class are shown in the table below. See
the code example ReminderManyTimes.java for an example of using the
schedule(TimerTask task, long delay, long period) method.

Timer Method Description


schedule(TimerTask task, long Schedules the task to run after delay milliseconds
delay)
schedule(TimerTask task, Schedules task to run at the specified time
java.util.Date time)
schedule(TimerTask task, Schedules task to run first at the specified firstTime and then at
java.util.Date firstTime, long intervals of period milliseconds
period)
schedule(TimerTask task, long Schedules task to run first after delay milliseconds and then at
delay, long period) intervals of period milliseconds

A note on working with Dates and Times in Java


To work with dates and times in Java, you use the java.util.Date class. The Calendar
class can also be used to perform date and time arithmetic. For example, to schedule a
task for a particular time:

//Get the Date corresponding to 11:01:00 pm today.


Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 1);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();

timer = new Timer();


timer.schedule(new RemindTask(), time);

Note: there is also a javax.swing.Timer class that can be used in GUIs.

10 ThreadGroups
If you are working with a multi-threaded program, you can group your threads into
named groups. This allows you to carry out actions, such as setting priority and
setting as a daemon on each group of threads.
This is done using the ThreadGroup class.

If a thread is created without specifying a ThreadGroup, it is added to the same group


as the thread that created it. Normally, this group is the main group – which is created
by the Java VM when a program starts up.
The main group for an applet may have a name other than main.
The Thread class has constructors that take a ThreadGroup object as a parameter.

For example, if you want to add your thread to a different group, you can do
something like the following:

Page 18 of 19
8966484.doc FBE – Computer Science Dept

ThreadGroup myThreadGroup = new ThreadGroup(


"My Group of Threads");
Thread myThread = new Thread(myThreadGroup,
"a thread for my group");

To find out what group a thread is in, you can do this:


theGroup = myThread.getThreadGroup();

At this stage, it is ulikely that you will need to group threads – it is usually sufficient
to allow the Java VM to handle all threads in the main group.
There are various methods on the ThreadGroup class that can be invoked to get
information on or change properties of threads in the group.

Notes prepared by: FBE Computer Science Department.

Page 19 of 19

Você também pode gostar