Threads, Processes and Multitasking: Java® Tutorial
Threads, Processes and Multitasking: Java® Tutorial
We can create a new thread by instantiating our class, and we run it by calling the start() method that we inherited
from class Thread.
MyClass a = new MyClass();
a.start();
This approach for creating a thread works fine from a technical standpoint. Conceptually, however, it does not make
that much sense to say thatMyClass "is a" Thread. All that we are really interested in doing is to provide
a run() method that the Thread class can execute. The next approach is geared to do exactly this.
Implementing the Runnable Interface
In this approach, we write a class that implements the Runnable interface. The Runnable interface requires us to
implement a single method named run(), within which we place all code that is to be executed within the thread.
class MyClass implements Runnable {
// ...
public void run() {
// All code to be executed within the thread goes here.
}
}
We can create a new thread by creating a Thread object from an object of type MyClass. We run the thread by calling
the Thread object's start()method.
MyClass a = new MyClass;
Thread t = new Thread(a);
t.start();
3. The LifeCycle of a Thread
(Ref. Java® Tutorial)
A thread can be in one of four states during its lifetime:
new - A new thread is one that has been created (using the new operator), but has not yet been started.
runnable - A thread becomes runnable once its start() method has been invoked. This means that the code in
the run() method can execute whenever the thread receives CPU time from the operating system.
blocked - A thread can become blocked if one of the following events occurs:
o The thread's sleep() method is invoked. In this case, the thread remains blocked until the specified number
of milliseconds elapses.
o The thread calls the wait() method of an object. In this case, the thread remains blocked until either the
object's notify() method or itsnotifyAll() method is called from another thread. The calls
to wait(), notify() and notifyAll() are typically found within synchronizedmethods of the object.
o The thread has blocked on an input/output operation. In this case, the thread remains blocked until the i/o
operation has completed.
dead - A thread typically dies when the run() method has finished executing.
Note: The following methods in the java.lang.Thread class should no longer be used, since they can lead to
unpredicable behavior: stop(),suspend() and resume().
The following example illustrates various thread states. The main thread in our program creates a new
thread, Thread-0. It then starts Thread-0, thereby making Thread-0 runnable so that it prints out an integer every 500
milliseconds. We call the sleep() method to enforce the 500 millisecond delay between printing two consecutive
integers. In the meantime, the main thread proceeds to print out an integer every second only. The output from the
program shows that the two threads are running in parallel. When the main thread finishes its for loop, it
stops Thread-0.
We maintain a variable, myThread, which initially references Thread-0. This variable is polled by the run() method to
make sure that it is still referencing Thread-0. All we have to do to stop the thread is to set myThread to null. This will
cause the run() method to terminate normally.
class MyClass implements Runnable {
int i;
Thread myThread;
public MyClass() {
i = 0;
}
// This will terminate the run() method.
public void stop() {
myThread = null;
}
// The run() method simply prints out a sequence of integers, one every half second.
public void run() {
// Get a handle on the thread that we are running in.
myThread = Thread.currentThread();
// Keep going as long as myThread is the same as the current thread.
while (Thread.currentThread() == myThread) {
System.out.println(Thread.currentThread().getName() + ": " + i);
i++;
try {
Thread.sleep(500); // Tell the thread to sleep for half a second.
}
catch (InterruptedException e) {}
}
}
}
class Threadtest {
public static void main(String[] args) {
MyClass a = new MyClass();
Thread t = new Thread(a);
// Start another thread. This thread will run in parallel to the main thread.
System.out.println(Thread.currentThread().getName() + ": Starting a separate thread");
t.start();
// The main thread proceeds to print out a sequence of integers of its own, one every second.
for (int i = 0; i < 6; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
// Tell the main thread to sleep for a second.
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {}
}
// Stop the parallel thread. We do this by setting myThread to null in our runnable object.
System.out.println(Thread.currentThread().getName() + ": Stopping the thread");
a.stop();
}
}
4. Animations
Here is an example of a simple animation. We have used a separate thread to control the motion of a ball on the
screen.
anim.html
<HTML>
<BODY>
<APPLET CODE="Animation.class" WIDTH=300 HEIGHT=400>
</APPLET>
</BODY>
Animation.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Animation extends JApplet implements Runnable, ActionListener {
int miFrameNumber = -1;
int miTimeStep;
Thread mAnimationThread;
boolean mbIsPaused = false;
Button mButton;
Point mCenter;
int miRadius;
int miDX, miDY;
public void init() {
// Make the animation run at 20 frames per second. We do this by
// setting the timestep to 50ms.
miTimeStep = 50;
// Initialize the parameters of the circle.
mCenter = new Point(getSize().width/2, getSize().height/2);
miRadius = 15;
miDX = 4; // X offset per timestep.
miDY = 3; // Y offset per timestep.
// Create a button to start and stop the animation.
mButton = new Button("Stop");
getContentPane().add(mButton, "North");
mButton.addActionListener(this);
// Create a JPanel subclass and add it to the JApplet. All drawing
// will be done here, do we must write the paintComponent() method.
// Note that the anonymous class has access to the private data of
// class Animation, because it is defined locally.
getContentPane().add(new JPanel() {
public void paintComponent(Graphics g) {
// Paint the background.
super.paintComponent(g);
// Display the frame number.
g.drawString("Frame " + miFrameNumber, getSize().width/2 - 40,
getSize().height - 15);
// Draw the circle.
g.setColor(Color.red);
g.fillOval(mCenter.x-miRadius, mCenter.y-miRadius, 2*miRadius,
2*miRadius);
}
}, "Center");
}
public void start() {
if (mbIsPaused) {
// Don't do anything. The animation has been paused.
} else {
// Start animating.
if (mAnimationThread == null) {
mAnimationThread = new Thread(this);
}
mAnimationThread.start();
}
}
public void stop() {
// Stop the animating thread by setting the mAnimationThread variable
// to null. This will cause the thread to break out of the while loop,
// so that the run() method terminates naturally.
mAnimationThread = null;
}
public void actionPerformed(ActionEvent e) {
if (mbIsPaused) {
mbIsPaused = false;
mButton.setLabel("Stop");
start();
} else {
mbIsPaused = true;
mButton.setLabel("Start");
stop();
}
}
public void run() {
// Just to be nice, lower this thread's priority so it can't
// interfere with other processing going on.
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
// Remember the starting time.
long startTime = System.currentTimeMillis();
// Remember which thread we are.
Thread currentThread = Thread.currentThread();
// This is the animation loop.
while (currentThread == mAnimationThread) {
// Advance the animation frame.
miFrameNumber++;
// Update the position of the circle.
move();
// Draw the next frame.
repaint();
// Delay depending on how far we are behind.
try {
startTime += miTimeStep;
Thread.sleep(Math.max(0,
startTime-System.currentTimeMillis()));
}
catch (InterruptedException e) {
break;
}
}
}
// Update the position of the circle.
void move() {
mCenter.x += miDX;
if (mCenter.x - miRadius < 0 ||
mCenter.x + miRadius > getSize().width) {
miDX = -miDX;
mCenter.x += 2*miDX;
}
mCenter.y += miDY;
if (mCenter.y - miRadius < 0 ||
mCenter.y + miRadius > getSize().height) {
miDY = -miDY;
mCenter.y += 2*miDY;
}
}
}