Consider this code...
1 zzz.java
import java.applet.*; public class zzz extends Applet implements Runnable { }
That is not really the kind of code you can tear from limb to limb, but let us have a go. When we compile this code, an error called "class zzz must be declared abstract" pops up. This is because whenever we need a thread, we have to use implements Runnable. But a run() is also required.
2 import java.applet.*; public class zzz extends Applet implements Runnable { public void run() { showStatus("In Run"); } }
The run() is specified here. The showStatus() does the work of showing whatever you pass as a parameter in statusbar of your window. Here when we execute, we only get the message "Applet started". The run() does not get called as yet. Now, ladies and gentlemen, we come to the concept of threads. To set the ball rolling (or more specifically, the run()), we need to have a thread. Because the Runnable ...runtime... So here we go.
Unless you've not been sleeping lately, you must have realised that we define an object t that looks like a Thread. In the init() we initialise the thread. After all this effort, the thread still does not start to weave! Well, we forgot to assossiate the thread with the run(). For doing this, we have a function called start() in the Thread class. Since t, our thread looks like Thread, we can use the start() by keying it in as t.start(). So here we go...3 import java.applet.*; public class zzz extends Applet implements Runnable { Thread t; public void init() { t = new Thread(); } public void run() { showStatus("In Run"); } }
4 import java.applet.*; public class zzz extends Applet implements Runnable { Thread t; public void init() { t = new Thread(); t.start(); } public void run() { showStatus("In Run"); } }
5 import java.applet.*; public class extends Applet { Thread t; public void init() { t = new Thread(this); t.start(); } public void run() { showStatus("In Run"); } }
There, we finally have our first thread running and kicking. When we run the above program, we see "In Run" displayed at the bottom of our window. And like it or not, that is where the status is shown by default. Now that we can rest assured our thread works, let us make it do something for us. Retain the above code. In the run(), add the following lines..
Now that we are calling the repaint(), we also have to have a paint(). So we include it as follows..i++; repaint();
Now that we are using Graphics, we have to import java.awt.* . When you compile and run the program now, the output is sadly simplistic. The status, as before, drawls "In Run". At the coordinates 10, 20 we see "i...1", which is not that picturesque afterall. But wait, that explains one thing. When the run() gets called, the value of i is incremented by 1. So, i increases from 0 to 1. Now the repaint() calls the paint(). Here the drawString() puts "i...1" at 10, 20. That implies that the run() function gets called once, does its work and then the program does nothing further. To demonstrate this concept a little more clearly, let us make the run() do a little more work. Retaining the above code as it is, add the following lines to the run()...public void paint(Graphics g) { g.drawString("i..." + i, 10, 20); }
This time, i is first displayed as 1, then 2 and then 3. This is because the repaint() is being called thrice. (In reality, though, you only see "i...3" owing to the speed of your computer).i++; repaint(); i++; repaint();
As expected, this will show us the value of i being incremented non-stop. This is because of the while(true) loop. (For those who are confused about the while construct, the while loop continues till the condition (specified with it) is true. As soon as it becomes false, the loop stops. Here since we have the condition permanantly as true, it is an endless loop.)while(true) { i++; repaint(); }
When you execute this program, you'll see that wherever you click, the button follows it and is displayed at that coordinates. The value of i changes along with it.6 import java.applet.*; import java.awt.*; public class zzz extends Applet implements Runnable { Thread t; int i; Button b; public void init() { t = new Thread(this); t.start(); b = new Button("hell"); add(b); } public void run() { while(true) { i++; repaint(); } } public boolean mouseUp(Event e, int x, int y) { b.reshape(x,y,30,50); return true; } public void paint(Graphics g) { g.drawString("i..."+i,10,20); } }
This program draws the images for you with the button behaving in the same way as in the earlier program. This explains, in a simple way, the potential and the function of threads. Without a thread, we could not think of performing two tasks at the same time. For instance, if we were to display a set of images continously and at the same time try to trap the click of a mouse (with mouseUp()), there was no way we could do it. With a thread, we can have programs working independently. (A point to be noted here is that the images, or the *.gif files were put by us in the directory where we have our *.java and the *.class files). 87 import java.applet.*; import java.awt.*; public class zzz extends Applet implements Runnable { int i = 0, j = 1, k = 0; Image m[]; Thread t; Button b; public void init() { m = new Image[17]; for (i=0; i < 17; i++) { m[i]=getImage(getCodeBase(),"T"+j+".gif"); j++; } t=new Thread(this); t.start(); b= new Button("hell"); add(b); } public void run() { while (true) { repaint(); k++; if (k==17) k=0; } } public boolean mouseUp(Event e, int x, int y) { b.reshape(x,y,40,50); return true; } public void paint(Graphics g) { g.drawImage(m[k],10,25,this); } }
This program introduces the concept of a thread being suspended, resumed, started or stopped. A thread (or the independent program) when started, can be suspended(stopped temporarily), then resumed for as many times as required. But once stopped, it cannot be started again.import java.applet.*; import java.awt.*; public class zzz extends Applet implements Runnable { int i = 0, k = 0, j = 1; Image m[]; Thread t; Button a,b,c,d; public void init() { m = new Image[17]; for (i=0; i<17; i++) { m[i]=getImage(getCodeBase(),"T"+j+".gif"); j++; } t=new Thread(this); a= new Button("start"); b=new Button("stop"); c=new Button("suspend"); d=new Button("resume"); add(a); add(b); add(c); add(d); } public void run() { while (true) { repaint(); k++; if (k==17) k=0; } } public boolean action(Event e, Object o) { if("start".equals(o)) { t.start(); return true; } if("stop".equals(o)) { t.stop(); return true; } if("suspend".equals(o)) { t.suspend(); return true; } if("resume".equals(o)) { t.resume(); return true; } return false; } public void paint(Graphics g) { g.drawImage(m[k],10,25,this); } }
More than one thread
9 import java.applet.*; import java.awt.*; public class zzz extends Applet implements Runnable { int i = 0; Thread a,b; public void init() { a = new Thread(this); b = new Thread(this); a.start(); b.start(); } public void run() { while(true) { i++; repaint(); showStatus(a.getName()); showStatus(b.getName()); } } public void paint(Graphics g) { g.drawString("i..."+i,10,20); } }
The above program has two threads a and b. Both of them call the same run(). To show this effect, we put showStatus() which will tell us which thread is running. Actually, since both the threads are calling the same run(), the display output will alternate between the two threads. This is because we provide getName() as the parameter. The getName() will get the name of the current thread. (That's not a joke)
Here everytime you click, a new thread is being created because inside the mouseUp() we initialize a thread everytime. Therefore, the showStatus now will show the name of a new thread everytime you click.10 import java.applet.*; import java.awt.*; public class zzz extends Applet implements Runnable { Thread a; public boolean mouseUp(Event e, int x, int y) { a = new Thread(this); a.start(); return true; } public void run() { while(true) { showStatus(a.getName()); } } }
11 import java.applet.*; import java.awt.*; public class zzz extends Applet implements Runnable { Thread a; public boolean mouseUp(Event e, int x, int y) { a = new Thread(this); a.start(); return true; } public void run() { while(true) { showStatus(Thread.currentThread().getName()); } } }
This one is not much different from the previous one. Only this time, we get as an output the names of all the threads. Let me explain. In the earlier program, everytime you clicked a new thread was being created but since the getName() was being assossiated with that thread only (a.getName()), in the run() we could only see the name of that thread. Here again a new thread is being created, but due to the currentThread(), we get the name of all the threads, continuously.
12 import java.applet.*; import java.awt.*; class ttt extends Thread { int i; zzz b; public ttt(zzz a) { b=a; } public void run() { while(true) { i++ ; b.repaint(); } } } public class zzz extends Applet { ttt t; public void init() { t = new ttt (this); t.start(); } public void paint(Graphics g) { g.drawString("i..."+t.i,10,30); } }
Instead of having all the threads use the same run(), we can derive a class from the Thread class. As seen in the above program, we have our own class ttt which looks like Thread. This class has a run() in it. Now when we define an object t that looks like ttt, we can exclusively use the run() of ttt.
13 import java.applet.*; import java.awt.*; class ttt extends Thread { int i; zzz b; public ttt(zzz a) { b=a; i=0; } public void run() { while(true) { i++ ; b.repaint(); } } } class uuu extends Thread { int j; zzz c; public uuu(zzz d) { c=d; j=0; } public void run() { while(true) { j++; c.repaint(); } } } public class zzz extends Applet { ttt t; uuu u; public void init() { t = new ttt (this); u = new uuu (this); t.start(); u.start(); t.setPriority(Thread.MIN_PRIORITY); u.setPriority(Thread.MAX_PRIORITY); } public void paint(Graphics g) { g.drawString("i..."+t.i,10,30); g.drawString("j..."+u.j,10,60); } }
To make the concept of deriving from Thread a trifle clearer, we have two threads here u and t. We also introduce here the concept of priority. Yep! you can set priority for the threads. Here we give t a maximum priority and u a minimum one. Therefore the value of i, which is related to the t thread will increase at a slower rate and that of j will be faster.
14 import java.applet.*; import java.awt.*; class ttt extends Thread { int i; zzz b; public ttt(zzz a) { b=a; i=0; } public void run() { while(true) { b.repaint(); i++ ; if ( i== 17) i=0; } } } class uuu extends Thread { int j; zzz c; public uuu(zzz d) { c=d; j=0; } public void run() { while(true) { c.repaint(); j++; if(j==8) j=0; } } } public class zzz extends Applet { ttt t; uuu u; int p,q; Image m[]; Image n[]; public void init() { t = new ttt (this); u = new uuu (this); t.setPriority(Thread.MIN_PRIORITY); u.setPriority(Thread.MAX_PRIORITY); m = new Image[17]; n = new Image[8]; q=1; for(p=0; p<17;p++) { m[p] = getImage(getCodeBase(),"T"+q+".gif"); q++; } q=1; for(p=0; p<8;p++) { n[p] = getImage(getCodeBase(),"B"+q+".gif"); q++; } t.start(); u.start(); } public void paint(Graphics g) { g.drawImage(m[t.i],10,30,this); g.drawImage(n[u.j],150,30,this); } }
Here we have two animations at the same time. And by now you must be well-versed with animation techniques. Two arrays of *.gif are displayed successively. If you find the images are running at a preposterously fast pace, you can set priorities for them.
15 import java.applet.*; import java.awt.*; class ttt extends Thread { int i; zzz b; Graphics g; public ttt(zzz a) { b=a; i=0; g=b.getGraphics(); } public void run() { while(true) { g.drawImage(b.m[i],10,20,b); i++ ; if ( i== 17) i=0; } } } class uuu extends Thread { int j; zzz c; Graphics g; public uuu(zzz d) { c=d; j=0; g=c.getGraphics(); } public void run() { while(true) { g.drawImage(c.n[j],150,20,c); j++; if(j==8) j=0; } } } public class zzz extends Applet { ttt t; uuu u; int p,q; Image m[]; Image n[]; public void init() { t = new ttt (this); u = new uuu (this); t.setPriority(Thread.MIN_PRIORITY); u.setPriority(Thread.MAX_PRIORITY); m = new Image[17]; n = new Image[8]; q=1; for(p=0; p<17;p++) { m[p] = getImage(getCodeBase(),"T"+q+".gif"); q++; } q=1; for(p=0; p<8;p++) { n[p] = getImage(getCodeBase(),"b"+q+".gif"); q++; } t.start(); u.start(); } }
In the previous programs, we have relied on the paint() to put the images on the screen. But that, besides making the code longer, also adds a lot of flickering to the animation. One way to remove this is to use getGraphics(), as is shown above.
16 import java.applet.*; import java.awt.*; class ttt extends Thread { int i; zzz b; Graphics g; public ttt(zzz a) { b=a; i=0; g=b.getGraphics(); } public void run() { while(true) { g.drawImage(b.m[i],10,20,b); i++ ; if ( i== 17) i=0; } } } class uuu extends Thread { int j; zzz c; Graphics g; public uuu(zzz d) { c=d; j=0; g=c.getGraphics(); } public void run() { while(true) { g.drawImage(c.n[j],150,20,c); j++; if(j==8) j=0; try { sleep(1000); } catch(Exception e) { } } } } public class zzz extends Applet { ttt t; uuu u; int p,q; Image m[]; Image n[]; public void init() { t = new ttt (this); u = new uuu (this); m = new Image[17]; n = new Image[8]; q=1; for(p=0; p<17;p++) { m[p] = getImage(getCodeBase(),"T"+q+".gif"); q++; } q=1; for(p=0; p<8;p++) { n[p] = getImage(getCodeBase(),"b"+q+".gif"); q++; } t.start(); u.start(); } }
As the images refresh too fast in the last program, you can use the sleep() to delay their drawing a little. A thread can be made to work slower by asking it to sleep. The try and catch might remind you of baseball, but it is Java's novel way of trapping any errors that might pop up during the execution of the program.
Here we manouvre with three threads. Two of them take care of simplistic animation (which must have become second nature to you by now) and the third takes of a button which moves everytime you click.17 import java.applet.*; import java.awt.*; class ttt extends Thread { int i; zzz b; Graphics g; public ttt(zzz a) { b=a; i=0; g=b.getGraphics(); } public void run() { while(true) { g.drawImage(b.m[i],10,20,b); i++ ; if ( i== 17) i=0; b.showStatus("i..."+i); } } } class uuu extends Thread { int j; zzz c; Graphics g; public uuu(zzz d) { c=d; j=0; g=c.getGraphics(); } public void run() { while(true) { g.drawImage(c.n[j],150,20,c); j++; if(j==8) j=0; c.showStatus("j..."+j); } } } public class zzz extends Applet { ttt t; uuu u; int p,q; Image m[]; Image n[]; Button o; public void init() { t = new ttt (this); u = new uuu (this); m = new Image[17]; n = new Image[8]; q=1; for(p=0; p<17;p++) { m[p] = getImage(getCodeBase(),"T"+q+".gif"); q++; } q=1; for(p=0; p<8;p++) { n[p] = getImage(getCodeBase(),"b"+q+".gif"); q++; } t.start(); u.start(); o = new Button("hell"); add(o); } public boolean mouseUp(Event e, int x, int y) { o.reshape(x,y,40,30); return true; }
As you must have noticed, till now we have been initializing t by passing 'this' as a parameter. That means, in plain English, that the run() will be called from the current class, i.e., zzz. But this time, we've replaced 'this' with u, which looks like our own class uuu. So the run() specified in the class uuu will be called. Meanwhile, uuu is a class that has not been derived from the Thread class, but it implements Runnable. 1918 import java.applet.*; import java.awt.*; class uuu implements Runnable { int i; zzz b; public uuu(zzz a) { b=a; i=0; } public void run() { while(true) { i++; b.repaint(); } } } public class zzz extends Applet { Thread t; uuu u; public void init() { u = new uuu(this); t = new Thread(u); t.start(); } public void paint(Graphics g) { g.drawString("i..." + u.i, 10, 40); } }
This was just another example of how a class which has not been derived from Thread can work. Here we have two threads and our pet variables i and j being incremented everytime.import java.applet.*; import java.awt.*; class uuu implements Runnable { int i; zzz b; public uuu(zzz a) { b=a; i=0; } public void run() { while(true) { i++; b.repaint(); } } } class ttt extends Thread { zzz b; int j; public ttt(zzz a) { b=a; j=0; } public void run(() { j++; repaint(); } } public class zzz extends Applet { Thread h; uuu u; ttt t; public void init() { u = new uuu(this); h = new Thread(u); t = new ttt(this); h.start(); t.start(); } public void paint(Graphics g) { g.drawString("i..."+u.i,10,40); g.drawString("j..."+t.j,10,80); } }