Skapa en applets med trådar/threads
Multitask är ett begrepp som ofta förekommer i datasammanhang idag. Multitask är helt enkelt flera programvaror
som tillåtes att köras samtidigt i en och samma miljö. Antalet processorer kan vara en eller flera. Dessa program har
också möjlighet att sända information till varandra. Multitask = förmågan att kunna göra flera saker på en gång.
En av de mera komplexa funktionerna i Java är just att man relativt enkelt kan skriva program som kan arbeta i en
miljö med flera saker på gång samtidigt.
I Java kallas dessa samtida uppgifter för trådar/threads, medan metoden kallas multitrådar/multithreading. Trådar
/Threading är mycket användbart vid animationer och databassökningar samt andra tillfällen då bakgrundsprocesser
behövs. För att göra det enklare att följa kommer vi att använda trådar omväxlande med det engelska order threads
där det passar in bättre.
Detta kapitel skall introducera dig i applets med trådar, eller lära dig att köra flera program på en gång:
 Using an interface with a program
 Skapa threads
 Starta och stoppa threads
 Pausa en thread
 Ladda en hemsida från en applet
 Fånga upp fel
 Displaying an applet with other Web page elements
Applet som bläddrar genom länkar
För att få djupare förståelse över hur applets med trådar fungerar kommer vi att skriva en applet som kommer att
automatiskt bläddra genom en rad länkar och runt igen med en liten paus för varje länk.
Dessa fem länkar kommer att vara föremål för bläddringen:
 http://java.sun.com
 http://www.ludd.luth.se/~steen/project
 http://www.javaworld.com
 http://www.nasa.gov
 http://www.linux.org
 http://www.redhat.com
Men vi väntar lite med att skriva programmet, vi måste ha lite mera verktyg först.
Klass deklarationerna
Det första du måste göra för att kunna skapa en applet med ovan beskrivna funktion är att importera en rad klasser
som kan behövas. Thread klassen, som är en del av java.lang klassen behövs, den innehåller verktyg och
funktioner för att kunna starta och stoppa eller pausa en tråd. Alla tre kommer att användas i programmet osm skall
bläddra, vi döper det reda nu till Bladder. (Urinblåsa på Engelska)
Klassen java.awt behövs för att kunna använda, Graphics, för att visa text i appletfönstret. Klaseen
java.net kommer att användas när vi öppnar www adresserna. Klassen java.applet används när du vill
beordra browsern att ladda en ny sida. Slutligen klassen java.awt.event behövs för händelser typ musklickar:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
Efter det att du importerat är du redo att använda klasserna som döljer sig däri.
Du kan nu börja appleten som vi skall skriva med följande:
public class Bladder extends Applet
implements Runnable, ActionListener {
På detta vis skapar vi Bladder klassen som en subklass till Applet klassen. Den använder också instruktionen
implements, som möjliggör arv från några andra klasser än Applet klassen. Klasserna Runnable och
ActionListener kallas för gränssnitt eller interfaces. Ett interface är en speciell typ av klass som enbart är
tillgänglig om man hämtar den med instruktionen implements. Ett interface utökar möjligheterna i en klass. I
detta fall erbjuder Runnable funktioner och objekt som behövs för att kunna bli en thread, bakgrundsprocess.
Genom att lägga till denna klass kan du starta bakgrundsjobb genom att starta dessa med instruktionen run().
ActionListener tillåter precis som namnet anger, appleten att svara på händelser, till exempel musen och andra
liknande. En av funktionerna i denna speciella klass, actionPerformed() anropas när en musknapp trycks ned.
Iordningställa variabler
Det första som måst egöras i klassen/programmet Bladder är att skapa variabler och objekt som behövs i hela
programmet, klassveriabler och objekt.
Vi skapar därför två matriser som består av textsträngar, vi döper dem till pageTitle för titelraden i HTML
dokumentet och den andra döper vi till pageLink där vi lagrar URL:en till sidan, pekaren:
String[] pageTitle = new String[6];
URL[] pageLink = new URL[6];
pageTitle kan då lagra de sex hemsidornas titelrader som vi skall låta programmet bläddra mellan.
En speciell variabeltyp kallad URL lagrar hemsidans adress, en sådan adress-pekare kallas också för URL.
URL innehåller förutom adressen alla funktioner och attribut som behövs för att hålla reda på en hemside adress och
ladda den i en Web-browser. Båda matriserna initieras utan värden eller innehåll om du så vill, tomma, vi ger med
innehållet senare
De två sista sakerna vi behöver göra är att skapa en heltalsvariabel som vi döper till current och ytterligare ett
objekt som vi döper till runner den är av typen Thread:
int current = 0;
Thread runner;
current skall användas till att lagra nuvarande sida som visas, och genom att ändra dess värde bläddrar vi genom
sidorna.
Thread objektet runner representerar den enda tråden i detta programmet, du kommer att anropa runner när du
vill starta, stoppa eller pausa någon operation i appleten vi skriver, det vill säga om denna skall köras parallellt med
något annat..
Starta med init()
Funktionen init() körs automatiskt när en applet först startas, efter det att den lästs in av Webbläsaren. I detta
exempel kommer vi använda init () för att lagra värden I de två matriserna som i skapade för denna applet.
Samtidigt skapar vi också en knapp som man skall kunna klicka på, knappen dyker upp när appleten körs.
Så här går det till:
public void init() {
Color background = new Color(255, 255, 204);
setBackground(background);
pageTitle[0] = "JavaSoft";
pageLink[0] = getURL("http://java.sun.com");
pageTitle[1] = "Ingenjörsfirman Stéen";
pageLink[1] = getURL("http://www.ludd.luth.se/~steen/project");
pageTitle[2] = "JavaWorld";
pageLink[2] = getURL("http://www.javaworld.com");
pageTitle[3] = "Nasa homepage";
pageLink[3] = getURL("http://www.nasa.gov ");
pageTitle[4] = "Linux homepage.";
pageLink[4] = getURL("http://www.linux.org");
pageTitle[5] = "Linux RedHat";
pageLink[5] = getURL("http://www.redhat.com");
Button goButton = new Button("Go");
goButton.addActionListener(this);
add(goButton);
}
De två första programraderna ställer in bakgrundsfärgen I appletfönstret.
Textsträngarnas initialvärden sätts parvis, titeln för hemsidan och dess UR adress.
Adressen lagras med funktionen getURL, som du senare skapar för detta program.
De tre sista raderna skapar knappen, som dyker upp I appletfönstret. Knappen döps också till det fyndiga namnet
goButton och knappen märks också visuellt för användaren med texten Go.
addActionListener(this); Gör det möjligt för programmet att reagera när någon trycker på knappen.
Reden med add() lägger in knappen I appletfönstret så den syns.
Felhantering
Det finns flera typer av fil som man kan råka ut för, kompileringsfel, programkörningsfel och illegala matematiska
operationer samt illegala och felaktiga värden. Den första kan man inte göra så mycket åt, mer än att reducera antalet
buggar. De andra typerna uppkommer under det att ett program körs och en stackars användare får se den hemska
felkoden plus det faktum att dennes programkörning havererat, har ni någonsin provat Microsoft Windows ?
I Java och alla andra seriösa programspråk förekommer dock en eller flera mekanismer för att ta hand om
förutsägbara fel. Man låter då programmet ta hand om felet, normalt sett avbryts körningen, och programmeraren
måste lägga in speciell kod för åtgärder.
Kommandot try Java är ett exempel på en sådan funktion. Try “provar” att till exempel öppna en angiven hemsida
via dess adress, misslyckas det på grund av olika anledningar fångas felet upp och man måste fånga felet med ett
annat kommando, catch. Catch fångar felet innan det har uppstått på riktigt och krashat programmet och kanske
hela den operativa miljön.
Funktionen getURL() tar en textsträng som argument, textsträngen kontrolleras med avseende på att det skall vara
en korrekt URL sträng. Är strängen korrekt som adress returneras korrekt adress från funktionen, motsatsen en
felaktig adress returnerar ingenting en NULL sträng.
Här är ett exempel på en felhantering med try och catch:
URL getURL(String urlText) {
URL pageURL = null;
try { pageURL = new URL(getDocumentBase(), urlText); }
catch (MalformedURLException m) { }
return pageURL;
}
Funktionen ovan med felkontrollen beskriver följande moment:
 Vilken typ av information som skall returneras, i detta fall ett URL objekt. Om det är fel på den förväntade
adressen kommer inget att returneras.
 Funktionens namn getURL.
 Inparametrarna, en textsträng vid namn urlText.
Instruktionen try följt av { och } utför själva testen om URL:ens adress är korrekt formaterad. Skulle den inte
vara det genereras ett fel som fångas upp av funktionen catch.
För att krångla till det är catch instruktionen också tvungen att fånga upp felkoden som en
inparameter och funktionen är utrustad med förmågan att utföra åtgärder direkt vid fel mellan { och }.
MalformedURLException är felrapportören.
I de fall då adressen är korrekt returneras den korrekta URL adressen, om ej returneras ingenting.
Skärmuppdateringar med Paint() funktionen
Som sagts innan används paint() för att uppdatera skärmen med ny information, text eller grafik, eller rättare
sagt appletfönstret. Händelsen som utlöser detta kan vara Web-browsern eller operativsystemet, om fönstrets storlek
ändras på något sätt eller annan uppdateringshändelse. Naturligtvis kan paint() också anropas ”manuellt” av
programkod inne i en applet.
Det vill säga om du anropar repaint(); i en applet tvingas paint() att utföras omedelbart. Till exempel om du
skriver ett animationsprogram och du förflyttar en bild från ett ställe till ett annat, så bör du använda repaint för att
bilden skall visas på sitt nya ställe.
Appleten Bladder har en relativt kort programkod för sin paint():
public void paint(Graphics screen) {
screen.drawString(pageTitle[current], 5, 60);
screen.drawString("" + pageLink[current], 5, 80);
}
De två instruktionerna inne i funktionen skriver ut textrader på positionerna(x,y), vid (5, 60) och (5, 80). Den första
raden skriver ut pageTitle matrisens nuvarande innehåll, titelraden. Den andra raden skriver ut adressen till
URL’en.
Att starta en ”Thread” tråd
Ett av de objekten som behövs för detta program är en thread, denna kallar vi för runner. För att kunna starta denna
måste vi ange några värden och hur den skall startas.
I denna applet kommer runner att startas i bakgrunden när start() anropas och soppas när stop() anropas.
start() funktionen anropas tvi tå tillfällen, direkt efter init() och varje gång programmet återstartas efter att
varit stoppat.
En applet stoppas varje gång som användaren byter från en hemsida med en applet till en annan. Den återstartas när
användaren återvänder igen, om denne gör det. Följande programkod illustrerar start() funktionen som tillhör
Bladder appleten:
public void start() {
if (runner == null) {
runner = new Thread(this);
runner.start();
}
}
Dessa programrader gör bara en sak, om runner inte redan startats, startas ett nytt bakgrundsobjekt.
Objektet runner är lika med noll om den inte är startad, så man skall kunna utreda om den körs eller ej, vi utför
kontrollen med ett if villkor.
Uttrycket runner = new Thread(this); skapar ett nytt bakgrundsobjekt med ett argument, instruktionen
this. Genom att använda this på detta sätt kommer appleten självt att bli det program som körs i runner
thread. runner.start(); Startar den egentliga trådkörningen.
Köra en thread/tråd
Funktionen run() är där trådens huvudarbete äger rum. Den är jämförbar med main() funktionen i en Java
applikation. I Bladder appleten, beskriver följande programkod huvudfunktionen funktionen run():
public void run() {
while (true) {
repaint();
current++;
if (current > 5)
current = 0;
try { Thread.sleep(10000); }
catch (InterruptedException e) { }
}
}
Alla instruktionerna i denna funktion är en del av while slingan vilken är dömd att köras i all oändlighet, ty dess
villkor är alltid sant. Det enda sättet att stoppa slingan är att anropa funktionen stop()som automatiskt anropas när
Webbrowsern stängs av eller användaren flyttar sig till en annan hemsida.
Funktionen run() anropar först funktionen repaint(); för att i sin tur få paint() funktionen att utföras.
Efter dessa anrop räknas variabeln current upp med ett, skulle dess värde överstiga 5, kommer den att nollställas
igen och proceduren upprepas om och om igen.
Variabeln current används inne i funktionen paint() för att utreda vilken hemsida som skall visas. Ändras
värdet i current kommer att resultera i att den hemsidan visas nästa gång paint() anropas.
Det finns ytterligare två funktioner, try-catch det är felhanteringsinstruktionerna. Funktionen
Thread.sleep(10000); gör en liten paus om 10000 millisekunder i programexekveringen. Det för att
användaren skall ha tid nog att läsa namnet på webbsidan och dess adress.
Instruktionen catch hanterar alla tänkbara fel, InterruptedException som tänkas uppstå medan
Thread.sleep() utförs. Felet uppträder om någonting försöker avbryta tråden medan den försökte sova,
sleep().
Avsluta en Thread
Funktionen stop() anropas varje gång appleten stoppas på grund av att användaren byter till en annan hemsida, så
det är bästa stället at stoppa threaden är just i denna funktion. Funktionen stop() som vi använder i Bladder
appleten skulle kunna se ut på följande sätt:
public void stop() {
if (runner != null) {
runner.stop();
runner = null;
}
}
Villkoret if kontrollerar om där finns någon tråd, runner=null. Skulle runner vara lika med noll betyder det att vi
inte behöver stoppa något, andra fallen så måste vi avsluta tråden och tilldela denna noll.
Hantera musklickar
Allt som användaren gör med musen eller tangentbordet kallas för händelse events. Den process som tar hand om
dessa händelser kallas för eventhandling.
Det sista vi behöver ta hand om i Bladder appleten är musklickar. När du klickar på knappen GO, skall
Webbrowsern öppna den listade sidan.
Funktionen actionPerformed()anropas varje gång en musknapp trycks ned. Följande programkod deklarerar
actionPerformed() som passar i appleten Bladder:
public void actionPerformed(ActionEvent evt) {
runner.stop();
AppletContext browser = getAppletContext();
if (pageLink[current] != null)
browser.showDocument(pageLink[current]);
}
Det första som händer är att threaden runner stoppas, de två följande instruktionerna skapar ett nytt objekt kallat
browser från typen AppletContext objektet, en kontroll utförs om den webbadress som visas just nu är tillåten. I
de fall då current är skilt ifrån noll, är det helt okej att visa denna sida. Det görs med showDocument funktionen i
AppletContext klassen av funktioner.
Laboration: Rullande länkar
Vi har nu belyst alla delar av appleten Bladder, det skulle då vara möjligt att skriva ett program för att testa om vi
hade rätt. Som vanligt, starta din ordbehandlare och skriv in lista 14.1, spara som Bladder.java
Lista 14.1. Bladder.java.
1: import java.applet.*;
2: import java.awt.*;
3: import java.awt.event.*;
4: import java.net.*;
5:
6: public class Bladder extends Applet
7: implements Runnable, ActionListener {
8:
9: String[] pageTitle = new String[6];
10: URL[] pageLink = new URL[6];
11: int current = 0;
12: Thread runner;
13:
14: public void init() {
15:
Color background = new Color(255, 255, 204);
16:
setBackground(background);
17:
pageTitle[0] = "JavaSoft";
18:
pageLink[0] = getURL("http://java.sun.com");
19:
pageTitle[1] = "Ingenjörsfirman Stéen";
20:
pageLink[1] = getURL("http://www.ludd.luth.se/~steen/project");
21:
pageTitle[2] = "JavaWorld";
22:
pageLink[2] = getURL("http://www.javaworld.com");
23:
pageTitle[3] = "Nasa homepage";
24:
pageLink[3] = getURL("http://www.nasa.gov ");
25:
pageTitle[4] = "Linux homepage.";
26:
pageLink[4] = getURL("http://www.linux.org");
27:
pageTitle[5] = "Linux RedHat";
28:
pageLink[5] = getURL("http://www.redhat.com");
29:
Button goButton = new Button("Go");
30:
goButton.addActionListener(this);
31:
add(goButton);
32: }
33:
34: URL getURL(String urlText) {
35:
URL pageURL = null;
36:
try { pageURL = new URL(getDocumentBase(), urlText); }
37:
catch (MalformedURLException m) { }
38:
return pageURL;
39: }
40:
41: public void paint(Graphics screen) {
42:
screen.drawString(pageTitle[current], 5, 60);
43:
screen.drawString("" + pageLink[current], 5, 80);
44: }
45:
46: public void start() {
47:
if (runner == null) {
48:
runner = new Thread(this);
49:
runner.start();
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:
public void run() {
while (true) {
repaint();
current++;
if (current > 5)
current = 0;
try { Thread.sleep(10000); }
catch (InterruptedException e) { }
}
}
public void stop() {
if (runner != null) {
runner.stop();
runner = null;
}
}
public void actionPerformed(ActionEvent evt) {
runner.stop();
AppletContext browser = getAppletContext();
if (pageLink[current] != null)
browser.showDocument(pageLink[current]);
}
}
Efter det att du lyckats kompilera programmet med javac kompilatorn måste du också skriva en hemsida där du
kan placera appleten.
Öppna din ordbehandlare och skapa en ny fil med din ordbehandlare, skriv in lista 14.2 och döp den till
Bladder.html när du sparar den.
Lista 14.2. Bladder.html.
1: <html>
2: <head>
3: <title>Homepage with Java and Linux</title>
4: </head>
5: <body bgcolor="#C4C4C4">
6: <font face="Arial" size=3>
7: <table>
8: <tr>
9:
10: <td bgcolor="#FFCCFF" width=300 valign="TOP" align="CENTER">
11: <h2>Homer's Home Page</h2>
12: <p>Welcome! This page is under construction.
13: </td>
14:
15: <td bgcolor="#FFFFCC" width=200 valign="TOP" align="RIGHT">
16: <i><b>Some interesting links:</b></i>
17: <applet code="Bladder.class" height=100 width=200>
18: </applet>
19: <center>
20: <i>Click to visit</i>
21: </center>
22: </td>
23:
24: </tr>
25: </table>
26: </font>
27: </body>
28: </html>
När du är klar med det, prova att läsa filen med appletviewer. Du kan prova programmet utan hemsidan också,
men då kommer ingen formatering äga rum samt länkarna går ej att klicka fram.
Du kan också använda en Webbrowser som kan hantera Java 1.1 program,
Summering
Förhoppningsvis har du nu börjat få en liten bild över hr du kan skapa bakgrundsjobb med java i applets.
Flertalet av funktionerna vi arbetar med i applets anropas automatiskt såsom paint()och händelser.
Frågor och Svar
1. Varför behövs inte java.applet.Applet i klassdeklarationen för appleten Bladder?
Svar: Den behövs inte därför att import delen av de klasser vi behöver gör att alla klasser
från java.applet klassen är tillgängliga.
2. Vad är visten med trådar och bakgrundsprocesser när Bladder enbart har en thread
?
Svar: Multithreading har sina fördelar även om det bara rör sig om en thread som i detta
program. De är enkla att starta och stoppa samt pause från ett program. Utan dem har du inte
samma kontroll.
Frågor
1. Vilka klasser måste importeras för att kunna köra threads?
(a) Runnable
(b) Thread
(c) Applet
2. När en klass har initierats som en thread, vilken funktion kommer att anropas när den
börjar köra ?
(a) start()
(b) run()
(c) init()
3. Du beundrar andra programmerares arbete som har skapat en applet som hanterar fyra
olika samtida uppdrag. Vad skulle du säga till honom/henne ?
(a) "Ha… det är inte hälften så häftigt som Nabster."
(b) "Du är luften under mina vingar!"
(c) "Häftiga trådar!"
Svar
1. a., 2. b., 3. c.
Övningar
Om du gillar att skriva HTML baserade dokument, skapa då din egen version av Bladder där du bläddrar mellan
dina favoritlänkar. Blanda gärna med grafik och texter.
Skriv om Ouch appleten från föregående kapitel, men använd threads i stället och pausa en sekund mellan varje
kalkyl då stadsskulden växer.