I liked to write a short guide for
threads in java. It is because I could not find the existing materials much helpful. None of them dealt with this in a pedagogically clear way. They confuse the reader with materials such as "monitor" and native operating system or by mixing the
thread usage with other pieces of a complicate program that deviate the attention to those pieces. Many of them want only to demonstrate an animated program is possible without explaining the
thread by itself. Here I use a thread for moving from one image to another image. It is like a "Clock Pulse" or a "tick-tack" When it ticks we have one image when it tacks it shows another image. When the clock pulse is up it shows one image. When the pulse is down it shows the other image. When you use a thread in a java class you should implement java.lang.Runnable() interface. This interface contains the signature for the
run() method that you write for your class. You also need a start method
start() to initiate a thread. As a counterpart to tick of
run() method we need a
reset() method for tack of our clock. We need a method that, in case, takes us out of the tick-tack into a place that we become in control of doing other tasks. This is normally a boolean flag that tests something we predicted in a corner of the tick or in a corner of the tack. I do it simple by counting the tick-tacks and after certain number of loops I stop the animation, through that counter or through the flag. The quartet of
start() -
run() -
reset() -
flag() is all I need.
start(): starts tick-tack;
run() and
reset(): make the tick-tack runs and runs for ever;
flag(): stops the tick-tack to go to other jobs if you like to stop it (it inhibits the clock like the hardware
inhibit signal). I cannot change names of the
run() and
start() but I can change names of the other two. I call my
reset() as
other() to emphasis its job, to prevent confusing it with inhibit. I call my
flag() method as
isDone() in fashion of java boolean classes. I do not move anything on the screen to demonstrate animation. I only switch between two still pictures to learn how the
thread is working between two states. This facilitate my future progress. I had an icon image, "Bella.gif" I used Windows 7 Microsoft Picture Manager and flipped it horizontally and saved the flipped image as "bellb.gif" Then I switched back and forth between these two images. You can see that, tick and tack are both within a never-ending while loop, as far as the thread is not killed; that is, is not null. We call our flag method
isDone() to find a way, or rather to arrange, to terminate that loop, for example, if the bell has done fifty tolls. At that time we put the toll counting back to zero for the next round. Here, I embed my code,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
| package Forward;
/**
*
* author Peter Jones
*/
// I do not extend java.lang.Thread, I'd rather to implement java.lang.Runnable to be more straight forward
public class Ex1aThread extends javax.swing.JFrame implements java.lang.Runnable{
/** Creates new "form" Ex1bThread */
public Ex1aThread() {
aPanel = new javax.swing.JPanel();
aLabel = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setPreferredSize(new java.awt.Dimension(50, 110));
add(aPanel);
aPanel.add(aLabel);
pack();
// I start a thread just after packing.
// I could start it from a button or a mouse click
// or any other event
start();
}
/** Start when browser is loaded or button pushed. **/
public final void start() {
// if thread is not active start it
if (fThread == null){
fThread = new java.lang.Thread (this);
fThread.start();
}
} // start
/** The thread loops to draw each frame.**/
public void run() {
// Loop through animation frames
while ( fThread != null){
// Sleep 100msecs between frames
// Change this value for smoothness
try{
Thread.sleep (100);
// I am counting number of loops
++bellTolls;
// in each loop I "refresh" image icon of the label
aLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("Bella.gif")));
}
catch (InterruptedException e) { }
// Now go to other frame
other();
// I check if bell tolls fifty times I kill fThread by making it null
if (this.isDone()) fThread = null;
}
}// run ends
// Your other frame comes here.
public void other(){
// Sleep 100msecs between frames
// Change this value for smoothness
try{
Thread.sleep (100);
// in each loop I "refresh" image icon of the label to other image
aLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("Bellb.gif")));
}
catch (InterruptedException e) { }
}
/* Boolean allows you to terminate this thread, if you like, and go to other tasks.
* I used it to provide a flag for counting. Bell stops after fifty tolls.
* The true flag kills the thread, returns the counter to zero to be ready
*/
public boolean isDone() {
boolean temp=false;
//COUNTS is assumed fifty times.
if(bellTolls==COUNTS) {
temp=true;
// I reset the toll counting
bellTolls=0;
}
// returning true kills the fThread
return temp;
}
//
// Next main
//
public static void main(String args[]) {
new Ex1aThread().setVisible(true);
}
// Variables declaration - do not modify
// For simple GUI
//
private javax.swing.JLabel aLabel;
private javax.swing.JPanel aPanel;
// Variables declaration - do not modify
// For thread animation
//
Thread fThread;
int bellTolls=0; // this is toll counter
final int COUNTS=50;
// End of variables declaration
}
|
Click
here to see the application (please click on Open/Run and look at top-left corner ). Ifyou save the "
jar" file in your computer you can use "7z" decompression utility to extract source file and image file.
I have created a Java Swing Ex1Thread.java class to put my animation over it. That Swing comes in the constructor "
public Ex1Thread { bloh, bloh, bloh, ...}" up to the line that we see
start().
start() method is invoked after packing the Swing frame by
pack() method. Up to this point we do not concentrate on given codes. They are already part of our knowledge. From
start() the
thread task starts. By putting the
start() in the constructor we have started our thread from the point that the class becomes created. (That is the reason for modifying
start() as a
final or as
private method. Had we called it somewhere out of the constructor it simply could override the interface. Ignore these details here.) It is easy to start it from other points in the program, for instance, from action of a button. Other tutorials have done it from a button, but it is confusing since we encounter with event dispatching, then. To prove my control over the threads, in the next example I interrupt between tick-tacks with a third thread such that I have a tick-talk-tack. In this fashion I can manage as many threads in my hand. Here, I embed my code,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
| package Forward;
/**
*
* author Peter Jones
*/
public class Ex1bThread extends javax.swing.JFrame implements java.lang.Runnable{
/** Creates new form Ex1bThread */
public Ex1bThread() {
aPanel = new javax.swing.JPanel();
aLabel = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setPreferredSize(new java.awt.Dimension(50, 110));
add(aPanel);
aPanel.add(aLabel);
pack();
start();
}
/** Start when browser is loaded or button pushed. **/
public final void start() {
if (fThread == null){
fThread = new java.lang.Thread (this);
fThread.start();
}
} // start
/** The thread loops to draw each frame.**/
public void run() {
// Loop through animation frames
while ( fThread != null){
// Sleep 100msecs between frames
// Change its value to adjust its smoothness.
try{
Thread.sleep (100);
++bellTolls;
aLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("Bella.gif")));
}
catch (InterruptedException e) { }
// Now go to other frame
other();
//To appreciate that you can invoke many threads as easy as one
//create a third thread to interrupt between tick and tack
anOther();
if (this.isDone()) fThread = null;
}
}// run ends
// Your other frame comes here.
public void other(){
// Sleep 100msecs between frames
// Change its value to adjust its smoothness.
try{
Thread.sleep (100);
aLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("Bellb.gif")));
}
catch (InterruptedException e) { }
}
// Your yet another frame comes here.
// It is t he third thread comes interrupting inthe middle of tick tack
public void anOther(){
// Sleep 100msecs between frames
// Change its value to adjust its smoothness.
try{
Thread.sleep (100);
aLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("Sun.gif")));
}
catch (InterruptedException e) { }
}
/* Boolean allows you to terminate this thread, if you like, and go to other tasks.
* I used it to provide a flag for counting. Bell stops after fifty tolls.
* The true flag kills the thread, returns the counter to zero to be ready
*/
public boolean isDone() {
boolean temp=false;
if(bellTolls==COUNTS) {
temp=true;
bellTolls=0;
}
return temp;
}
//
// Next main
//
public static void main(String args[]) {
new Ex1bThread().setVisible(true);
}
// Variables declaration - do not modify
// For simple GUI
//
private javax.swing.JLabel aLabel;
private javax.swing.JPanel aPanel;
// Variables declaration - do not modify
// For thread animation
//
Thread fThread;
int bellTolls=0;
final int COUNTS=50;
// End of variables declaration
}
|
Click
here to see the application (please click on Open/Run and look at top-left corner ). I put a Helios (personified Sun) between bell tolls. It is done by invoking the method
anOther()