14 Trådar - SectorData

January 9, 2018 | Author: Anonymous | Category: Engineering & Technology, Datavetenskap, Java Programming
Share Embed Donate


Short Description

Download 14 Trådar - SectorData...

Description

14 Trådar  

Trådar (Thread) Gränssnittet Runnable

Kap 14: Sid 2

Med trådar kan man få något att ske vid sidan av det ordinarie programmet. Man kanske vill att en klocka ska stå och ticka, eller att en text ska förflyttas över skärmen. I Java är det enkelt att arbeta med trådaar, Threads Testa klockövningarna i början. Sedan ska du koncentrera dig på övningarna där gränssnittet Runnable ingår. Försök att få ett fungerande Asteroidspel. Försök lösa någon eller några av de uppgifter som presenteras sist i kapitlet.

265333640

© Ove Lundgren

2

Kap 14: Sid 3

Trådar (Thread) De flesta program är en-trådiga: Allt sker i viss ordning. Två processer kan inte ske samtidigt. Java är mång-trådigt (multi-threaded). Det finns möjlighet att arbeta med en eller flera trådar (threads) utöver själva “programtråden”. Man kan dela upp ett program i flera samtidigt exekverande processer. Man kan få flera saker kan ske “samtidigt”. Vi ska låta våra animeringar styras av trådar.

tråd

Man skapar ett trådobjekt genom att ärva från en klass som heter Thread (tillhör paketet java.lang) Klassen Thread har en metod som heter run(). Den metoden överskuggas: Där beskrivs vad tråden ska göra. Ett trådobjekt har också metoden start()med vilka exekveringen av run()-metoden startas. Ett trådobjekt stoppas genom att sätta dess referens till null (referensen “pekar” inte på något objekt) Övningarna visar hur det hela fungerar: Övning: Klockan blir en tråd Vi skriver en klass, KlockTrad, som ärver av Thread. Koden finns på nästa sida. Ur denna klass ska vi sedan skapa trådobjekt i en applet. (Klassen KlockTrad bygger på klassen Klocka i kapitel 7. Repetera!) Kommentarer till koden: Klassen KlockTrad har instansvariablerna diam för diametern och (x, y) för klockans placering. Vidare är ivall intervallet mellan varje rörelse hos visaren uttryckt i millisekunder. Variabeln sek uttrycker det antal sekunder som klockan visar. Vi deklarerar vi en referens, gr, till ett grafiskt objekt (så att vi kan rita…) I konstruktorn får instansvariablerna (utom sek) sina värden. Metoden setTid() används för att ge variabeln sek ett initialvärde. I metoden visa() ritas själva urtavlan. Visarens poition beror av värdet på variabeln sek så som beskrivs i kapitel 7. Sedan följer run()-metoden som innehåller en beskrivning av vad tråden ska göra: En while(true)-loop är en oändlig loop, det vill säga en loop som kommer att upprepas hur många gånger som helst ( i vårt fall så länge tråden är aktiv). I en sådan loop ligger satser som gör följande: Vi räknar upp en sekund för varje “varv” i loopen med sek++ Metoden visa() anropas varvid urtavlan med visarens nya läge ritas. Klassmetoden Thread.sleep(ivall) ger en fördröjning på ivall millisekunder. Metoden sleep ska ligga i try-catch-konstruktion. Därefter fortsätter loopen, det vill säga en ny urtavla ritas osv, osv. Skriv in koden på nästa sida. Spara som KlockTrad.java och kompilera.

265333640

© Ove Lundgren

3

Kap 14: Sid 4 import java.awt.*; public class KlockTrad extends Thread { private int diam, x, y, sek, ivall; private Graphics gr; public KlockTrad (int d, int a, int b, int f, Graphics g) { diam = d; x = a; y = b; ivall = f; gr = g; } public void setTid(int s) { sek = s; } public void visa() { gr.setColor(Color.white); gr.fillOval(x-diam/2,y-diam/2,diam,diam); gr.setColor(Color.red); gr.drawOval(x-diam/2,y-diam/2,diam,diam); gr.fillOval(x-2,y-2,4,4); double v = - sek*2*Math.PI/60 + Math.PI/2; int r = diam/2-3; // visarens längd int px =x + (int)(r*Math.cos(v)); int py =y - (int)(r*Math.sin(v)); gr.drawLine(x,y,px,py); } public void run() { while(true) { sek++; visa(); try { Thread.sleep(ivall) ; } catch ( InterruptedException e ) { } } } } Nu skriver vi en applet. Kod på nästa sida. Här deklareras ett trådbjekt, alltså ett objekt ur vår klass, KlockTrad, som vi ger referensen u1 Vi deklarerar också ett grafiskt objekt, xg I appletens start()-metod låter vi xg bli referens till appletens grafiska objekt och skapar trådobjektet u1 Vi ger härvid klockan diametern 80 och placerar den i positionen (100,100). Vi anger vidare att klockan ska “ticka fram” en gång var 1000e millisekund och att den ska ritas med grafikobjektet xg (alltså i appleten) Med metoden u1.setTid(0); anger vi att klockan från början ska visa 0 (noll) sekunder. Så anropas tråd-objektets start()-metod, varvid tråden startar ( Trådens run()-metod exekverar )

265333640

© Ove Lundgren

4

Kap 14: Sid 5 I appletens stop()-metod anropas trådens stop()-metod (så att run() upphör att exekvera) Vidare “dödar” vi grafikobjektet xg.

Skriv in koden. Spara som KlockApplet.java och kompilera. Skriv också en html-fil som kan starta appleten. Provkör! Tråden startar. Klockan “tickar”…. import java.applet.*; import java.awt.*; public class KlockApplet extends Applet { private KlockTrad u1; private Graphics xg; public void start() { xg = getGraphics(); u1 = new KlockTrad(80,100,100,1000, xg); u1.setTid(0); u1.start(); } public void stop() { xg.dispose(); u1 = null; } }

I KlockApplet, deklarera ytterligare ett KlockTrad-objekt med referensen u2 Instansiera det med t ex u2 = new KlockTrad(50,200,200,100, xg); (Eftersom ivall får värdet 100 så kommer den klockan att gå betydligt snabbare…) Skriv in satserna

u2.start();

och u2= null;

i respektive metod.

Spara, kompilera, provkör. De båda klockorna “tickar” nu helt oberoende av varandra… Övning: Digitalur Skriv en klass, Digitalur, som ärver Thread och visar en digital klocka. Låt appleten KlockApplet skapa objekt ur klassen… Ett lösningsförslag finns på nästa sida…

265333640

© Ove Lundgren

5

Kap 14: Sid 6

// Digitalur.java import java.awt.*; public class Digitalur extends Thread { private int x, y, h, m, s; // Placering samt timma, minut, sekund private Font f; private Graphics gr; public Digitalur(int a, int b, Graphics g) { f = new Font("Courier",Font.BOLD,15); x = a; y = b; gr = g; } public void { this.h = this.m = this.s = }

setTid(int h, int m, int s) h; m; s;

private String tS(int t) // Metod som gör om ett tal till en { // två-teckens-sträng String s; if(t59) { s =0; m++;} if (m>59) { m = 0; h++;} if (h>23) h = 0; visa(); try { Thread.sleep(1000) ; } catch ( InterruptedException e ) { } } } }

265333640

© Ove Lundgren

6

Kap 14: Sid 7

Gränssnittet Runnable Det finns ytterligare ett (bekvämt) sätt att arbeta med trådar som man brukar använda bl.a. vid animering. Du vet sedan tidigare att en klass inte kan ärva metoder ur flera klasser, men att man med hjälp av gränssnitt (interface) kan “låna” metoder från andra klasser. Med gränssnittet Runnable kan man förse t ex en applet med metoden run(). Vi skriver alltså public minApplet extends Applet implements Runnable och lägger till run()-metoden: public void run() { ...

}

Så deklarerar och instansierar vi trådobjekt: private Thread minTraad; ... minTraad = new Thread(this); Observera att vi ska ha argumentet this i Thread-konstruktorn. Med argumentet this anger vi att tråden ska använda den run()-metod som ägs av this (dvs appleten) I appletens start()-metod ska tråden startas ( sker med minTraad.start(); ) och i stop()-metoden ska tråden stoppas ( sker med minTraad= null; ) Övning: RunJumbo Du har i flera övningar flytta omkring stackars Jumbo på olika sätt. I förra kapitlet skrev vi appleten DraJumbo där vi kunde flytta figuren genom att dra musen. Nu ska vi låta animeringen löpa automatiskt med hjälp av en tråd. Ta fram DraJumbo.java och gör ändringar och tillägg enligt koden på nästa sida. Här är några kommentarer till koden: Gränssnittet Runnable implementeras Trådobjeket t deklareras

run()-metod i denna applet

I appletens init()-metod:   

Trådobjeketet t instansieras med t = new Thread(this); Variabeln d anger hur mycket figuren ska flyttas i sidled i varje “steg” Trådobjeketet startas med t.start(); ( det vill säga run()-metoden startar…)

I appletens stop()-metod: 

Trådobjektet stoppas med t = null; ( run()-metoden stannar…)

I run()-metoden ligger en loop som itererar så länge t inte är null :    

Här ökar värdet på a (Jumbos horisontella position) Om a blir större än ett visst värde byts tecknet på d (så att figuren flyttas åt vänster nästa gång) Så kommer en fördröjning (Thread.sleep()-metoden i try-catch-konstruktion) Slutligen repaint();

265333640

© Ove Lundgren

7

Kap 14: Sid 8 import java.awt.*;

import java.applet.Applet;

public class RunJumbo extends Applet implements Runnable { private int a, b, d; private Image bild1; private Thread t; public void init() { bild1 = this.getImage(getCodeBase(),"jumbo.gif"); t = new Thread(this); a = 50; b = 50; d = 5; t.start(); } public void paint(Graphics g) { g.setColor(Color.blue); g.fillOval(30,30,100,100); g.drawImage(bild1,a,b,this); } public void stop() { t = null; } public void run() { while( t != null ) { a = a + d; if(a>200 || a < 0 ) d=-d; try { Thread.sleep(100) ; } catch ( InterruptedException e ) { } repaint(); } } }

Spara som RunJumbo.java Kompilera. Starta appleten med en html-fil Jumbo ”vandrar” fram och tillbaka över appletytan… Bilden ”fladdrar”. Vi ska komplettera med dubbelbuffring strax… Övning: Flytande text. Ta fram en gammal övning där man skriver in något i ett textfält, en beräkning sker och ett resultat skrivs ut. (exempelvis Cirkel.java ) Gör så att texten ”JAVA” sakta förflyttar sig över appleten från vänster till höger i en oändlig loop. Hanteringen ska givetvis skötas av en separat tråd… (Försöker du lägga hanteringen som i en loop i t ex paint()-metoden kommer den ordinarie programtråden hela tiden att vara upptagen och ingen inmatning blir möjlig…) Snygga sedan till appleten: Dubbelbuffra, avrunda beräknade resultat, gör den flytande texten större…

265333640

© Ove Lundgren

8

Kap 14: Sid 9 Övning: En knapp som stannar och startar om I appleten RunJumbo, gör följande tillägg: Importera paketet för händelsehantering:

import java.awt.event.*;

Implementera gränssnittet ActionListener: Deklarera en knapp:

... implements Runnable, ActionListener

private Button butt;

Deklarera en logisk variabel: private boolean aktiv = true; Instansiera knappen: butt = new Button("Start/Stop"); och lägg ut den på appleten med add(butt); Sätt lyssnare på knappen: butt.addActionListener(this); Lägg till metoden actionPerformed(): public void actionPerformed(ActionEvent e) { if(aktiv) { t=null; aktiv=false; } else { t = new Thread(this); t.start(); aktiv = true; } } Spara – kompilera – provkör Lägg in dubbelbuffring (Se ”checklistan” för dubbelbuffring i förra kapitlet…) Anmärkning: I Java version 1.1 fanns i klassen Thread metoden stop() för att stoppa en tråd. Vidare fanns metoden suspend() för att tillfälligt deaktivera en tråd samt metoden resume() för att åter aktivera en tråd. Dessa metoder kunde orsaka vissa fel och finns inte med Java2. Metoderna är deprecated (man kan kompilera i Java2, men får ett felmeddelande). Ovanstående metod med t = new Thread(this); t.start(); och t = null; fungerar i både Java och Java2 Övning: Runnable JumboFilm Ta fram övningen JumboFilm (eller JumboFilmDB) från förra kapitlet. I den appleten skapade vi ”filmen” genom att låta paint() anropa sig själv (via repaint() )     

Gör ändringar så att filmen i stället styrs av en tråd. Använd en array av Image-objekt för bilderna Använd MediaTracker Lägg in dubbelbuffring. Lägg in en knapp med vilken filmen kan startas/stoppas

Spara som JumboFilmRun.java

265333640

(Lösningsförslag på nästa sida…)

© Ove Lundgren

9

Kap 14: Sid 10 import java.awt.*; import java.applet.*; import java.awt.event.*; public class JumboFilmRun extends Applet implements Runnable, ActionListener { Image jumbo[] = new Image[6]; Image xbild; Thread t; Graphics xg; Button butt; MediaTracker mt; int i; boolean aktiv = false; public void init() { t = new Thread(this); xbild = createImage(200,200); xg = xbild.getGraphics(); butt = new Button("Film"); add(butt); butt.addActionListener(this); mt = new MediaTracker(this); for(int i=0; i < 6; i++) { jumbo[i] = this.getImage(getCodeBase(),"jumbo"+i+".gif"); mt.addImage(jumbo[i],0); } try{ mt.waitForID(0);} catch(InterruptedException e) {} i = 0; } public void stop()

{

t = null;

public void update(Graphics g)

xg.dispose(); } {

paint(g);

}

public void paint(Graphics g) { xg.setColor(Color.white); xg.fillRect(0,0,200,200); xg.setColor(Color.cyan); xg.fillOval(20,20,100,100); xg.drawImage(jumbo[i],50,50,this); g.drawImage(xbild,0,0,this); } public void run() { while(t!=null) { repaint(); try { Thread.sleep( 150) ; } catch ( InterruptedException e ) { } i++; if(i==6) i=0; } } public void actionPerformed(ActionEvent e) { if(aktiv){ t = null; } else { t = new Thread(this); t.start(); aktiv = !aktiv; }

}

}

265333640

© Ove Lundgren

10

Kap 14: Sid 11 Övning: Asteroiderna – igen! I förra kapitlet kompletterade vi klassen Asteroid så att objektet själv bestämde hur det skulle röra sig. I appleten VisaAsteroider animerade vi genom att röra musen över appletytan. Vi ska skriva om VisaAsteroider så att animeringen i stället drivs av en tråd. Ta fram VisaAsteroider.java. Gör ändringar enligt nedan och spara med namnet RunAsteroider.java // RunAsteroider.java import java.applet.*;

import java.awt.*;

import java.awt.event.*;

public class RunAsteroider extends Applet implements Runnable { Asteroid ast[] = new Asteroid[10]; Thread t; public void init() { t = new Thread(this); for(int i=0;i
View more...

Comments

Copyright � 2017 NANOPDF Inc.
SUPPORT NANOPDF