Taking Action: Threads

# Depending on your operating system and Java-enabled browser you may have noticed that the Mondrian and Flying Line programs tended to hog your CPU. On Windows NT HotJava stopped responding to my commands several thousand iterations into Mondrian, and I had to kill it from the Task List.

The paint loops in both Mondrian and FlyingLines are ideal for a thread, a separate stream of execution that takes place simultaneously and independently of everything else that might be happening (like responding to the programmer’s insistence to “Quit!, Damnit!”). Without threads an entire program can be held up by one CPU intensive task or, as in Flying Lines, one infinite loop, intentional or otherwise.

As a general rule all CPU intensive tasks should be placed in their own threads. Here’s one way to do it.

//Draw infinitely many random rectangles

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

public class ThreadedMondrian extends Applet implements Runnable {

int RectHeight, RectWidth, RectTop, RectLeft, AppletWidth, AppletHeight;
Color RectColor;
Thread kicker = null;
int pause;

public void init() {

Dimension d = size();
AppletHeight = d.height;
AppletWidth = d.width;
repaint();
}

public void paint(Graphics g) {

g.setColor(Color.black);
g.drawRect(0, 0, AppletWidth-1, AppletHeight-1);

for (int i=0; i < 10; i++) {
RandomRect();
g.setColor(RectColor);
g.fillRect(RectLeft, RectTop, RectWidth-1, RectHeight-1);
}

}

public void run() {
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

while (true) { // infinite loop
repaint();
try {
Thread.sleep(100);
}
catch (Exception e) {

}
}
}

public void start() {
if (kicker == null) {
kicker = new Thread(this);
kicker.start();
}
}

public void stop() {
kicker = null;
}

public void RandomRect() {
RectTop = Randomize(AppletHeight);
RectLeft = Randomize(AppletWidth);
RectHeight= Randomize(AppletHeight - RectTop);
RectWidth = Randomize(AppletWidth - RectLeft);
RectColor = new Color(Randomize(255),Randomize(255),Randomize(255));
}

private int Randomize(int range)
{
double rawResult;

rawResult = Math.random();
return (int) (rawResult * range);

}

}

We added four key things to Mondrian to make it threaded and a lot more CPU friendly.

# We specified that our applet implements Runnable.
# We added a run method.
# We added a start method.
# We added a stop method.

Let's look at them in more detail:

Our applet implements Runnable

Run Method
Start Method
Stop Method

Here's a threaded version of Flying Lines.

//Bounce lines around in a box

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

public class FlyingLines extends Applet implements Runnable {

int NUM_LINES = 25;
int gDeltaTop=3, gDeltaBottom=3;
int gDeltaLeft=2, gDeltaRight=6;
int AppletWidth, AppletHeight;
int gLines[][] = new int[NUM_LINES][4];

public void init() {

AppletWidth = size().width;
AppletHeight = size().height;

}

public void start() {
gLines[0][0] = Randomize(AppletWidth);
gLines[0][1] = Randomize(AppletHeight);
gLines[0][2] = Randomize(AppletWidth);
gLines[0][3] = Randomize(AppletHeight);
for (int i=1; i < NUM_LINES; i++ ) {
LineCopy(i, i-1);
RecalcLine(i);
}
repaint();
Thread t = new Thread(this);
t.start();

}

public void run () {

Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

while (true) {
for (int i=NUM_LINES - 1; i > 0; i–) {
LineCopy(i, i-1);
}
RecalcLine(0);
System.out.println(gLines[0][0] + “, ” + gLines[0][1] + “,” + gLines[0][2] + “, ” + gLines[0][3]);
repaint();
try {
Thread.currentThread().sleep(10);
}
catch (Exception e) {

}
}

}

public void paint(Graphics g) {

for (int i=0; i < NUM_LINES; i++) {
g.drawLine(gLines[i][0], gLines[i][1], gLines[i][2], gLines[i][3]);
}

}

private void LineCopy (int to, int from) {

for (int i = 0; i < 4; i++) {
gLines[to][i] = gLines[from][i];
}

}

public int Randomize( int range ) {
double rawResult;

rawResult = Math.random();
return (int) (rawResult * range);

}

private void RecalcLine( int i ) {

gLines[i][1] += gDeltaTop;
if ((gLines[i][1] < 0) || (gLines[i][1] > AppletHeight)) {
gDeltaTop *= -1;
gLines[i][1] += 2*gDeltaTop;
}

gLines[i][3] += gDeltaBottom;
if ( (gLines[i][3] < 0) || (gLines[i][3] > AppletHeight) ) {
gDeltaBottom *= -1;
gLines[i][3] += 2*gDeltaBottom;
}

gLines[i][0] += gDeltaLeft;
if ( (gLines[i][0] < 0) || (gLines[i][0] > AppletWidth) ) {
gDeltaLeft *= -1;
gLines[i][0] += 2*gDeltaLeft;
}

gLines[i][2] += gDeltaRight;
if ( (gLines[i][2] < 0) || (gLines[i][2] > AppletWidth) ) {
gDeltaRight *= -1;
gLines[i][2] += 2*gDeltaRight;
}

} //RecalcLine ends here

} // FlyingLines ends here

Comments are closed.