420 likes | 569 Vues
THREADS. thread= draad in het programma (pad) gewone applets = één thread, volgt één pad multithreading = er worden twee of meer paden gestart, die schijnbaar tegelijk worden uitgevoerd = pseudo-simultaan uitvoeren van meerdere taken doel : het isoleren van taken
E N D
THREADS • thread= draad in het programma (pad) • gewone applets = één thread, volgt één pad • multithreading = er worden twee of meer paden gestart, die schijnbaar tegelijk worden uitgevoerd = pseudo-simultaan uitvoeren van meerdere taken • doel: het isoleren van taken • hoe ?- een object aanmaken van de klasse Thread (gebruikmaken van de standaardklasse Thread) • - een object door een thread laten sturen (gebruikmaken van de interface Runnable) JAVA --- H7
THREADS – UITVOERING VOORBEELD JAVA --- H7
THREADS -- VOORBEELD (1) public class Onafh_threads extends Applet { private Biljart biljart; private Bal bal; public void init() { biljart = new Biljart( getGraphics(), 50, 50, 320, 200 ); bal = new Bal( getGraphics(),10,getBackground(),biljart); } public void paint( Graphics g ) { biljart.teken(); bal.stuiter(); } } JAVA --- H7
THREADS -- VOORBEELD (2) class Biljart // package-toegankelijkheid { private Graphics g; private int links, boven, rechts, onder; Biljart( Graphics g, int links, int boven,int rechts, int onder ) { this.g = g; this.links = links; this.boven = boven; this.rechts = rechts; this.onder = onder; } JAVA --- H7
THREADS -- VOORBEELD (3) int getLinks() { return links; } int getBoven() { return boven; } int getRechts() { return rechts; } int getOnder() { return onder; } JAVA --- H7
THREADS -- VOORBEELD (4) void teken() { int breedte = rechts - links,hoogte = onder - boven; g.setColor( Color.black ); g.drawRect( links, boven, breedte, hoogte ); g.setColor( Color.green ); g.fillRect( links+1, boven+1, breedte-1, hoogte-1 ); } } JAVA --- H7
THREADS -- VOORBEELD (5) class Bal { private Graphics g; private int grootte, x, y, dx = 3,dy = 2; private Color wisKleur; private Biljart biljart; public Bal( Graphics g, int grootte, Color wisKleur, Biljart biljart ) { this.g = g; this.grootte = grootte; this.wisKleur = wisKleur; this.biljart = biljart; } JAVA --- H7
THREADS -- VOORBEELD (6) public void teken( Color kleur ) { g.setColor( kleur ); g.fillOval( x, y, grootte, grootte );} public void verplaats() { if( x + dx <= biljart.getLinks() || x + dx + grootte >= biljart.getRechts() ) { dx = -dx; } if( y + dy <= biljart.getBoven() || y + dy + grootte >= biljart.getOnder() ) { dy = -dy; } x += dx; y += dy; } JAVA --- H7
THREADS -- VOORBEELD (7) public void stuiter() { x = biljart.getLinks() + 1; y = biljart.getBoven() + 1; while( true ) { teken( Color.red ); slaap( 10 ); teken( wisKleur ); verplaats(); } } public void slaap( int millisec ) { try { Thread.sleep( millisec ); } // static methode !! catch( InterruptedException e ) {} } } JAVA --- H7
THREADS -- VOORBEELD • Opmerkingen: • de grafische context wordt via de constructor doorgegeven aan de klassen Biljart en Bal, zodat je deze in alle methoden kan gebruiken • via getGraphics() kan de grafische context opgevraagd worden • de applet stopt niet! • de applet reageert niet op events (bijv. klikken op een button) ! JAVA --- H7
THREADS -- EVENTAFHANDELING • Oplossingen(1): • om events op te vangen maken we een tweede thread • hiervoor gebruiken we volgende methoden: • Thread(): de constructor • void start(): een thread starten • void stop(): een thread stoppen • void run():doet het eigenlijke werk; herdefiniëren! Wordt automatisch aangeroepen door de start()-methode!! Niet verwarren met start() en stop() van Applet!! JAVA --- H7
THREADS -- EVENTAFHANDELING • Oplossingen (2): • void sleep():laat de thread slapen (in milliseconden), een andere thread kan nu zijn werk uitvoeren (Not Runnable) • void suspend(): het runnen van de thread onderbreken (Not Runnable) • void resume(): de onderbreking ongedaan maken (Runnable) JAVA --- H7
THREADS -- LEVENSCYCLUS Levenscyclus van een Thread: JAVA --- H7
THREADS – STOPPEN VAN APPLET • Oplossingen: om de applet te doen stoppen als de pagina verlaten wordt en daarna opnieuw te starten : • Invoegen van een start() - en stop() -methode: • start(): wordt automatisch aangeroepen na het uitvoeren van de methode init() ofbij het terug vergroten van het venster (na verkleining tot icoon) • stop(): wordt automatisch aangeroepen bij het verlaten van de web-pagina met de applet of bij het verkleinen tot icoon JAVA --- H7
THREADS • Reageren op events: • invoeren van een tweede thread • eerste thread: reageren op muisevents (hoofdthread) • tweede thread: beweging van biljartbal over scherm • klasse Thread gebruiken als basisklasse voor de klasse Bal -> het balletje loopt in een eigen thread JAVA --- H7
THREADS • Bijkomende nuttige methoden: • static-methode currentThread(): om na te gaan welke thread momenteel aan het werk is • isAlive(): geeft true indien de thread gestart en nog niet gestopt is; kan dus zowel Runnable als Not Runnable zijn JAVA --- H7
THREADS – AANGEPAST VOORBEELD (1) public class Onafh_threads extends Appletimplements ActionListener { private Biljart biljart; private Bal bal; private Button startKnop, pauzeKnop, gadoorKnop, stopKnop; public void init() { biljart = new Biljart( getGraphics(), 50, 50, 320, 200 ); startKnop = new Button( "Start" );pauzeKnop = new Button( "Pauze" ); gadoorKnop = new Button( "Ga door" );stopKnop = new Button( "Stop" ); add( startKnop ); startKnop.addActionListener(this); add( pauzeKnop ); pauzeKnop.addActionListener(this); add( gadoorKnop ); gadoorKnop.addActionListener(this); add( stopKnop ); stopKnop.addActionListener(this); } JAVA --- H7
THREADS – AANGEPAST VOORBEELD (2) public void start() { if( bal == null ) { bal = new Bal( getGraphics(), 10, getBackground(), biljart ); bal.start(); // de thread starten } } public void stop() { if( bal != null ) // of if (bal.isAlive()) { bal.stop(); // de thread stopzetten bal = null; } } JAVA --- H7
THREADS – AANGEPAST VOORBEELD (3) public void paint( Graphics g ) { biljart.teken(); } public void actionPerformed( ActionEvent e) { if( e.getSource() == startKnop ) { if( bal == null ) { // hetzelfde als wanneer de applet wordt gestart bal = new Bal( getGraphics(), 10, getBackground(), biljart ); bal.start(); // de thread starten -> run() } } JAVA --- H7
THREADS – AANGEPAST VOORBEELD (4) if( e.getSource() == pauzeKnop ) if(bal != null ) bal.suspend(); // onderbreking if( e.getSource() == gadoorKnop ) if( bal != null ) bal.resume(); // hervatting if ( e.getSource() == stopKnop ) { if( bal != null ) { // run() wordt drastisch onderbroken bal.stop(); // de thread gaat dood bal = null; // de bal is niet meer in leven } } } } JAVA --- H7
THREADS – AANGEPAST VOORBEELD (5) Wijzigingen in de klasse Bal: class Bal extends Thread { //..... De functie stuiter() wordt nu de functie run()!! In de functie slaap(), gebruiken we de gewone functie sleep() uit de klasse Thread, want het balletje is zelf ook een Thread ! } JAVA --- H7
THREADS - tweede mogelijkheid • Thread aanmaken als subklasse van Thread • doch: • soms problemen wegens enkelvoudige overerving • mogelijke oplossing: opsplitsen in twee klassen! Voorbeeld: een applet, die herhaaldelijk geluid afspeelt door middel van au-files -> extends Applet! JAVA --- H7
THREADS - VOORBEELD (1) import java.applet.*; import java.awt.*; import java.net.*; // nodig voor URL public class Audio extends Applet { ThrGeluid thr; public void start() {URL url = getDocumentBase(); thr = new ThrGeluid(); thr.ac = getAudioClip(url,"Hi.au"); thr.start(); } JAVA --- H7
THREADS - VOORBEELD (2) public void stop() { thr.stop(); } public void paint(Graphics g) {g.drawString("Als de file hi.au in de huidige directory",10,30); g.drawString("staat, wordt nu geluid geproduceerd!",10,50); } } JAVA --- H7
THREADS - VOORBEELD (3) class ThrGeluid extends Thread { AudioClip ac; public void run() { for (;;) { ac.play(); try { Thread.sleep(1000); } catch (InterruptedException e) {} } } // geen constructor -> default-constructor } JAVA --- H7
THREADS -- RUNNABLE-INTERFACE • voorgestelde oplossing is niet ideaal !! • door gebruik te maken van de interface Runnable, kan alles opnieuw via één klasse • enkel implementatie van de run-methode en expliciet een object aanmaken van de klasse Thread: thr = new Thread(this); waarbij this het object is, dat nu door een thread wordt gestuurd, m.a.w. het object zelf is nu GEEN thread! JAVA --- H7
THREADS -- RUNNABLE-INTERFACE Aangepast voorbeeld: public class Audio extends Applet implements Runnable { Thread thr; AudioClip ac; public void init() { URL url = getDocumentBase(); ac = getAudioClip(url,"Hi.au"); } public void start() { thr = new Thread(this); thr.start(); } JAVA --- H7
THREADS -- RUNNABLE-INTERFACE public void stop() { thr.stop(); } public void run() { for (;;) { ac.play(); try { Thread.sleep(1000); } catch (InterruptedException e) {} }} public void paint(Graphics g) {g.drawString("Als de file hi.au in de huidige directory",10,30); g.drawString("staat, wordt nu geluid geproduceerd!",10,50);} } JAVA --- H7
THREADS -- UITVOERING TOEPASSING JAVA --- H7
THREADS -- VOORBEELD: DE KLOK class Timer extends Thread { private Aanvrager aanvrager; // de klok private int interval; // 1000 milliseconden = 1 seconde public Timer( Aanvrager aanvrager, int interval ) { this.aanvrager = aanvrager; this.interval = interval; } JAVA --- H7
THREADS -- VOORBEELD: DE KLOK public void run() { while( true ) { // wachten tot het interval voorbij is try { sleep( interval ); } catch( InterruptedException e ) {} // naar de aanvrager een bericht sturen aanvrager.tik(); } } } JAVA --- H7
THREADS -- VOORBEELD: DE KLOK interface Aanvrager { public void tik(); } JAVA --- H7
THREADS -- VOORBEELD: DE KLOK import java.util.*; // voor Date en Calendar class Klok extends Canvasimplements Aanvrager {private int seconden, minuten, uren; private int uurTovGMT; private boolean timerLoopt = false; final double tweePi = 2 * Math.PI; final double halfPi = Math.PI / 2; public Klok( int uurTovGMT ) // uurTovGMT = aantal uren verschil //tussen de tijd op deze plaats op aarde en Greenwich Mean Time {this.uurTovGMT = uurTovGMT; Timer timer = new Timer( this, 1000 ); timer.start(); } JAVA --- H7
THREADS -- VOORBEELD: DE KLOK public void paint( Graphics g ) { if( timerLoopt ) {// Bereken de hoeken van de wijzers double secondenHoek = halfPi - tweePi * seconden / 60; double minutenHoek = halfPi - tweePi * minuten / 60; double urenHoek = halfPi - tweePi * uren / 12 – tweePi / 12 * minuten / 60; // Teken de klok g.translate( 175, 150 ); JAVA --- H7
THREADS -- VOORBEELD: DE KLOK g.setColor( Color.cyan ); g.drawOval( -100, -100, 200, 200 ); g.setColor( Color.blue ); g.drawOval( -99, -99, 198, 198 ); // Teken de stippen op de klok g.fillOval( -4, -4, 9, 9 ); for( int u = 0; u < 12; u++ ) { double stipHoek = tweePi * u / 12; if( u % 3 == 0 ) { g.setColor( Color.cyan ); g.fillOval( (int) ( 90 * Math.cos( stipHoek ) - 3 ), (int) ( -90 * Math.sin( stipHoek ) - 3 ), 5, 5 ); } JAVA --- H7
THREADS -- VOORBEELD: DE KLOK else { g.setColor( Color.darkGray ); g.fillOval( (int) ( 90 * Math.cos( stipHoek ) - 2 ), (int) ( -90 * Math.sin( stipHoek ) - 2 ), 4, 4 ); } } JAVA --- H7
THREADS -- VOORBEELD: DE KLOK // Teken de wijzers g.setColor( Color.blue ); g.drawLine( 0, 0, (int) (55 * Math.cos( urenHoek ) ), (int) ( -55 * Math.sin( urenHoek ) ) ); g.drawLine( 0, 0, 0 + (int) ( 80 * Math.cos( minutenHoek )), (int) ( -80 * Math.sin( minutenHoek ) ) ); g.drawLine( 0, 0, 0 + (int) ( 95 * Math.cos( secondenHoek )), (int) ( -95 * Math.sin( secondenHoek ) ) ); } } JAVA --- H7
THREADS -- VOORBEELD: DE KLOK public void tik() { Date date = new Date(); Calendar calendar = new GregorianCalendar( new SimpleTimeZone(uurTovGMT*60*60*1000,null)); seconden = calendar.get(Calendar.SECOND); minuten = calendar.get(Calendar.MINUTE); uren = calendar.get(Calendar.HOUR); timerLoopt = true; repaint(); } } JAVA --- H7
THREADS -- VOORBEELD: DE KLOK public class AnalogeKlok extends Applet { private Klok klok; public void init() { setLayout( new BorderLayout() ); klok = new Klok( 1 ); add( "Center", klok ); } } JAVA --- H7
THREADS -- Dubbelbuffering Om flikkering bij animatie te voorkomen, kan men het scherm in de achtergrond opbouwen en het dan in zijn geheel tonen! Voorbeeld: twee bolletjes die bewegen in de wereld (= grid) private Image offscreenImage; // dubbel buffering private Graphics offscreenGraphics;//Graphics context //Herdefinitie van update uit Canvas Class, maar nu //zonder de achtergrond schoon te maken public void update( Graphics g ) { // doe geen background erase paint( g ); } JAVA --- H7
THREADS -- Dubbelbuffering //Herdefinitie van paint uit Canvas Class, maar nu met //dubbelbuffering public void paint( Graphics g ) { if( offscreenGraphics == null ) { offscreenImage = createImage( breedte, hoogte ); offscreenGraphics = offscreenImage.getGraphics(); } // maak het scherm schoon offscreenGraphics.setColor( Color.cyan ); offscreenGraphics.fillRect( 0, 0, breedte, hoogte ); //bepaal de kleur van de buitenrand en teken de rand offscreenGraphics.setColor( rand ? Color.red : Color.yellow ); JAVA --- H7
THREADS -- Dubbelbuffering for( int i = 0; i < GROOTTE; i++ ) offscreenGraphics.drawRect( i, i, breedte - i * 2, hoogte - i * 2 ); // teken de "grid" offscreenGraphics.setColor( Color.black ); for( int i = GROOTTE; i < breedte - GROOTTE; i += GROOTTE ) offscreenGraphics.drawLine( i, GROOTTE, i, hoogte-GROOTTE ); for( int i = GROOTTE; i < hoogte - GROOTTE; i += GROOTTE ) offscreenGraphics.drawLine( GROOTTE, i, breedte-GROOTTE,i ); // teken de bolletjes bolB.tekenen( offscreenGraphics ); bolW.tekenen( offscreenGraphics ); // en teken nu dan alles in het echt g.drawImage( offscreenImage, 0, 0, null ); } JAVA --- H7