La oss begynne med en repetisjon av hva som skjer når du kjører Javaprogrammet

Like dokumenter
Tråder Repetisjon. 9. og 13. mai Tråder

Inf Våren 2008 Tråder del 1 Parallelle programmer og felles data. Stein Gjessing, Institutt for informatikk, Universitetet i Oslo

Tråder Repetisjon. 9. og 13. mai Tråder

IN1010''1 Våren 2018 Tråder del'1. 3.'april 2018''

INF1010 Tråder J. Marit Nybakken Motivasjon. Å lage en tråd

Oversikt. Inf Våren Parallelle programmer og felles data. Hva er parallelle programmer I I. Hva er parallelle programmer?

IN Våren 2019 Tråder del mars 2019

INF Våren 2017 Tråder del 1

GUI («Graphical User Interface») del 2

INF Notater. Veronika Heimsbakk 10. juni 2012

INF1010, 22. mai Prøveeksamen (Eksamen 12. juni 2012) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

INF Våren 2016 Tråder del mars Stein Gjessing, Ins$tu' for informa$kk, Universitetet i Oslo. Ins$tu' for informa$kk

Stein Gjessing, Ins$tu' for informa$kk, Universitetet i Oslo

LITT OM OPPLEGGET. INF1000 EKSTRATILBUD Stoff fra uke September 2012 Siri Moe Jensen EKSEMPLER

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

Konstruktører. Bruk av konstruktører når vi opererer med "enkle" klasser er ganske ukomplisert. Når vi skriver. skjer følgende:

2 Om statiske variable/konstanter og statiske metoder.

INF2440 Prøveeksamen, løsningsforslag, 20 mai Arne Maus PSE, Inst. for informatikk

UNIVERSITETET I OSLO

Jentetreff INF1000 Debugging i Java

INF Våren Tråder. del 1. Stein Gjessing, Ins$tu' for informa$kk, Universitetet i Oslo. Ins$tu' for informa$kk

Forklaring til programmet AbstraktKontoTest.java med tilhørende filer Konto.java, KredittKonto.java, SpareKonto.java

UNIVERSITETET I OSLO

Avdeling for ingeniørutdanning Institutt for teknologi

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister Videre

I et Java-program må programmøren lage og starte hver tråd som programmet bruker. Er dette korrekt? Velg ett alternativ

Sortering med tråder - Quicksort

INF1000 EKSTRATILBUD. Stoff fra uke 1-5 (6) 3. oktober 2012 Siri Moe Jensen

INF 1010, vår 2005 Løsningsforslag uke 11

Synkronisering I. Kapittel 6. Tråd A. ferdig. t.varsle() u.vente() Tråd B. ferdig. tid

Side 1 av 11, prosesser, tråder, synkronisering, V. Holmstedt, HiO 2006

GUI («Graphical User Interface») del 2

Eksamen INF1010 V2009 Del B prøveeksamen V2010 Vekt 60 %

2 Om statiske variable/konstanter og statiske metoder.

Inf1010 oppgavesamling

INF 1000 høsten 2011 Uke september

Innhold. Forord Det første programmet Variabler, tilordninger og uttrykk Innlesing og utskrift...49

Repitisjonskurs. Arv, Subklasser og Grensesnitt

INF1000 undervisningen INF 1000 høsten 2011 Uke september

UNIVERSITETET I OSLO

Stein Gjessing, Ins$tu' for informa$kk, Universitetet i Oslo

INF1010 Tråder II 6. april 2016

Seminaroppgaver IN1010, uke 2

Stein Gjessing, Ins$tu' for informa$kk, Universitetet i Oslo

Stein Gjessing. Institutt for informatikk. Universitetet i Oslo. Institutt for informatikk

Synkronisering II. Kapittel 7. Betingelse oppfylt (0) liste. tråd-deskriptor. venteliste. tråd-deskriptor. tråd-deskriptor.

TDT4100 Objektorientert programmering

Stein Gjessing, Ins$tu' for informa$kk, Universitetet i Oslo

INF1000 (Uke 5) Mer om løkker, arrayer og metoder

i=0 Repetisjon: arrayer Forelesning inf Java 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker 0*0 0*2 0*3 0*1 0*4

Forelesning inf Java 4

UNIVERSITETET I OSLO

Blokker og metoder INF1000 (Uke 6) Metoder

UNIVERSITETET I OSLO

Programmering Høst 2017

Fra Python til Java. En introduksjon til programmeringsspråkenes verden. Dag Langmyhr

Oppsummering. Kort gjennomgang av klasser etc ved å løse halvparten av eksamen Klasser. Datastrukturer. Interface Subklasser Klasseparametre

public static <returtype> navn_til_prosedyre(<parameter liste>) { // implementasjon av prosedyren

Kapittel 8: Programutvikling

class Book { String title; } class Dictionary extends Book { int wordcount; } class CartoonAlbum extends Book { int stripcount; }

INF1010 våren 2017 Onsdag 25. januar. Litt om unntak i Java

Stein Gjessing, Institutt for informatikk, Universitetet i Oslo

IN1010. Fra Python til Java. En introduksjon til programmeringsspråkenes verden Dag Langmyhr

Introduksjon til objektorientert programmering

Hva er verdien til variabelen j etter at følgende kode er utført? int i, j; i = 5; j = 10; while ( i < j ) { i = i + 2; j = j - 1; }

public static <returtype> navn_til_prosedyre(<parameter liste>) { // implementasjon av prosedyren

INF1010 våren 2019 Onsdag 30. januar. Mer om unntak i Java (med litt repetisjon av I/O først)

Arv. Book book1 = new Book(); book1. title = "Sofies verden" class Book { String title; } class Dictiona ry extends Book {

UNIVERSITETET I OSLO

Løsningsforslag ukeoppg. 6: 28. sep - 4. okt (INF Høst 2011)

IN1010 våren Repetisjon av tråder. 15. mai 2018

IN1010. Fra Python til Java. En introduksjon til programmeringsspråkenes verden Dag Langmyhr

Leksjon 7. Filer og unntak

UNIVERSITETET I OSLO

INF1000 (Uke 4) Mer om forgreninger, While-løkker

Innhold uke 4. INF 1000 høsten 2011 Uke 4: 13. september. Deklarasjon av peker og opprettelse av arrayobjektet. Representasjon av array i Java

INF2440 Uke 6, v2017. Arne Maus PSE, Inst. for informatikk

I dag INF1000 (Uke 4) Mer om forgreninger, While-løkker. Tre måter å lese fra terminal. Repetisjon. Mer om forgrening While-løkker

Argumenter fra kommandolinjen

Oversikt. INF1000 Uke 1 time 2. Repetisjon - Introduksjon. Repetisjon - Program

Dagens tema: 12 gode råd for en kompilatorskriver

Programmering i C++ Løsningsforslag Eksamen høsten 2005

INF Seminaroppgaver til uke 3

Java PRP brukermanual

Dagens tema: Mer av det dere trenger til del 1

Læringsmål for forelesningen

Eksekveringsrekkefølgen (del 1) Oppgave 1. Eksekveringsrekkefølgen (del 2) Kommentar til oppgave 1. } // class Bolighus

UNIVERSITETET I OSLO

Fra Python til Java, del 2

Oppgave 1. Oppgave 2. Oppgave 3. Prøveeksamen i INF1000. Ole Christian og Arne. 23. november 2004

Lenkelister. Lister og køer. Kopi av utvalgte sider fra forelesningen.

Algoritmer og datastrukturer Kapittel 3 - Delkapittel 3.1

En implementasjon av binærtre. Dagens tema. Klassestruktur hovedstruktur abstract class BTnode {}

Feilmeldinger, brukerinput og kontrollflyt

I dag INF1000 (Uke 4) Mer om forgreninger, While-løkker. Tre måter å lese fra terminal. Tre måter å lese fra terminal.

Programmeringsspråket C

Prøveeksamen i INF1000. Ole Christian og Arne. 23. november 2004

Oppgave 1. INF1000 Uke 13. Oppgave 2. Oppgave 3. Er dette lovlige deklarasjoner (når de foretas inni en metode)? JA NEI

INF2440 Uke 6, v2015 om faktorisering av primtall + tre løsninger på et produsent/konsumentproblem. Arne Maus PSE, Inst.

Eksamensoppgaver 2014

Transkript:

K A P I T T E L 18 Tråder N år et program kjøres, utføres programsetningene i en bestemt rekkefølge. En tråd er det samme som denne programflyten, og i dette kapitlet skal vi se på hvordan vi starter og stopper en tråd, og hvordan vi kan ha flere tråder som kjører samtidig. La oss begynne med en repetisjon av hva som skjer når du kjører Javaprogrammet nedenfor. class Hei { public static void main(string[] args) { System.out.println("Hei 1"); System.out.println("Hei 2"); Etter kompilering starter du programmet ved å skrive java Hei på kommandolinja. Bak kulissene starter kjøresystemet til Java opp en tråd (eller en programflyt, om du vil) som kalles main-tråden. Main-tråden hopper til starten av main-metoden, som den forventer å finne i klassen Hei. Der følger den instruksjonene, en etter en i den rekkefølge de står. Først får vi skrevet ut Hei 1 og så Hei 2. Eksekveringen av tråden fortsetter så fra main-metoden hvis den inneholder kall på metoder, vi gjentar visse instruksjoner dersom de er inne i løkker, osv. Hele tiden holder programmet på med å utføre en og bare en instruksjon når programmet bare har en tråd. At det er en slik tråd, kan du oppdage hvis du prøver å starte en klasse uten main-metoden eller skriver feil klassenavn. Skriver vi for eksempel java hei (liten «h»), får vi følgende feilmelding før programmet avslutter:

334 18 Tråder Exception in thread "main" java.lang.noclassdeffounderror: hei Som du ser, har vi altså en tråd (eng. thread), som heter main. Unntaket blir kastet i denne tråden (se kapittel 17). 18.1 Stoppe og starte en tråd Det første vi nå skal se på, er hvordan vi kan få main-tråden til å ta en pause i eksekveringen. Vi benytter den statiske metoden Thread.sleep(long millisek). Metoden kan kaste et unntak, InterruptedException, som vi må fange opp dersom det skjer en feil. Programmet nedenfor skriver først ut en linje med teksten «skal sove...») og venter i minst to sekunder 11 før neste linje, som er «Nå er jeg våken», skrives ut. class SoveProgram { public static void main(string[] args) { long sek = 2 * 1000; // to sekunder System.out.println("Skal sove..."); try { Thread.sleep(sek); catch (InterruptedException e) {return; System.out.println("Nå er jeg våken"); 18.2 Lage en ny tråd La oss forsøke å lage en stoppeklokke. For hvert sekund som er passert, skal programmet skrive ut antall sekunder. Utskriften hvert sekund kan gjøres i følgende while-løkke: 11 Det kan ta litt lengre tid hvis prosessoren er opptatt med noe annet enn vårt program i det øyeblikket vår prosess har sovet i to sekunder. Som oftest vil forsinkelsen være så liten at vi kan se bort fra den.

18.2 Lage en ny tråd 335 boolean stop = false; int tid = 0; while (!stop) { System.out.println(tid++); try { Thread.sleep(1 * 1000); // ett sekund catch (InterruptedException e) {return; Problemet ligger i hvordan vi får stoppet og startet klokken. Løsningen er å la while-løkka kjøre i en egen tråd, mens vi i main-tråden styrer start og stopp av klokken. Vi begynner med å lage klassen og metoden while-løkka skal ligge i. Vi lar klassen være en subklasse av Thread-klassen. Thread-klassen inneholder en metode som automatisk kalles når man starter en ny tråd, nemlig run-metoden. I Thread-klassen gjør ikke run-metoden noe som helst, men vi redefinerer den (det er en virtuell metode) og får dermed følgende (foreløpige) klasse: class Stoppeklokke extends Thread { private volatile boolean stop = false; int tid = 0; while (!stop) { System.out.println(tid++); try { Thread.sleep(1 * 1000); // ett sekund catch (InterruptedException e) {return; Vi skal ikke gjøre kallet på run() direkte, i stedet skal vi kalle på en metode som heter public void start(), arvet fra Thread-klassen. Ved kall på start() skjer to ting: Systemet lager en ny tråd som starter opp run-metoden vår, og den gamle tråden, som utførte kallet på start, fortsetter umiddelbart etter kallstedet. Til slutt i Stoppeklokke-klassen vår trenger vi en metode for å stoppe

336 18 Tråder klokken. Ideelt sett burde metoden hete public void stop(), men det er det en utdatert metode i Thread-klassen som heter allerede, så vi må finne på et annet navn for eksempel kan vi kalle den public void end(). Denne metoden setter variabelen stop til verdien true, noe som vil føre til at while-løkka i run-metoden avsluttes. Siden run-metoden dermed er ferdig, dør stoppeklokketråden. Denne metoden kan vi dermed kalle fra main-tråden for å stoppe stoppeklokken. Slik ser det ferdige programmet ut: import easyio.*; class Klokke { public static void main(string[] args) { In stdin = new In(); System.out.println("Stopp og start med [ENTER]"); stdin.inline(); // Her lages stoppeklokke-objektet: Stoppeklokke stoppeklokke = new Stoppeklokke(); // og her settes den nye tråden i gang. stoppeklokke.start(); stdin.inline(); stoppeklokke.end(); class Stoppeklokke extends Thread { boolean stop = false; // blir kalt opp av superklassens start-metode. int tid = 0; while (!stop) { System.out.println(tid++); try { Thread.sleep(1 * 1000); // ett sekund catch (InterruptedException e) {return; Javabok-2011.pdf 336 03.07.2011 12:01:36

18.2 Lage en ny tråd 337 public void end() { stop = true; En alternativ måte å lage nye tråder på er å la en klasse implementere interfacet Runnable, som inneholder en abstrakt metode kalt run. En ny tråd lages da ved å benytte en konstruktør i Thread-klassen som tar et Runnable-objekt som parameter, og den startes ved å kalle på Thread-objektets start-metode. Vi kunne altså ha laget programmet over som følger: import easyio.*; class AlternativKlokke { public static void main(string[] args) { In stdin = new In(); System.out.println("Start og stopp med [ENTER]"); stdin.inline(); // Lag stoppeklokke-objektet: AlternativStoppeklokke stoppeklokke = new AlternativStoppeklokke(); // Lag tråden som skal kjøre det nye objektet: Thread stoppeklokketråd = new Thread(stoppeklokke); // Her settes den nye tråden i gang: stoppeklokketråd.start(); stdin.inline(); stoppeklokke.end(); class AlternativStoppeklokke implements Runnable { boolean stop = false; // Blir kalt opp av superklassens start-metode: int tid = 0; Javabok-2011.pdf 337 03.07.2011 12:01:36

338 18 Tråder while (!stop) { System.out.println(tid++); try { Thread.sleep(1 * 1000); // ett sekund catch (InterruptedException e) {return; public void end() { stop = true; En kanskje mer elegant metode er å la den nye tråden starte og stoppe seg selv. I klassen som implementerer Runnable legger vi til to metoder; start() og stop(): class AltStoppeklokke2 implements Runnable { Thread klokketråd = null; public void start() { if (klokketråd = null) { klokketråd = new Thread(this); klokketråd.start(); public void stop() { klokketråd = null; Thread dennetråden = Thread.currentThread(); while (dennetråden == klokketråd) {... som før For å starte og stoppe stoppeklokken over kan vi ganske enkelt kalle på de to Javabok-2011.pdf 338 03.07.2011 12:01:36

18.2 Lage en ny tråd 339 metodene start() og stop(). I start-metoden lages den nye tråden, hvis startmetode (fra Thread) kalles. Metoden Thread.currentThread() returnerer en peker til Threadobjektet som kalte på metoden det vil si denne tråden. Vi benytter dette i run-metoden, i betingelsen til while-løkka: Thread dennetråden = Thread.currentThread(); while (dennetråden == klokketråd) {... Siden de to pekerne i utgangspunktet peker på det samme Thread-objektet når run-metoden starter, utføres innholdet i while-løkka. public void stop() { klokketråd = null; Når denne metoden blir kalt (gjerne fra en annen tråd), settes klokketråden til å peke på null. Effekten er at betingelsen i run-metodens while-løkke blir usann, og run-metoden avsluttes. Det er altså to metoder for å lage en ny tråd: enten ved å subklasse Thread, skrive over run-metoden og kalle på start-metoden: class Traad1 extends Thread {... class Starter { new Traad1().start(); eller å implementere Runnable-interfacet. I så fall benyttes en annen konstruktør i Thread-klassen til å få laget selve tråd-objektet:

340 18 Tråder class Traad2 implements Runnable {... class Starter { new Thread(new Traad2()).start(); Hvorvidt du velger den ene eller den andre løsningen, blir opp til deg selv. 18.3 Samarbeid mellom tråder Alle tråder som er satt i gang av den samme virtuelle Java-maskinen, har felles adresserom. Det betyr at to tråder kan ha tilgang til de samme metoder og variabler noe vi kan se av stoppeklokkeprogrammet. I run-metoden, som kjøres av stoppeklokketråden, sjekkes sannhetsverdien av variabelen stop, og main-tråden endrer variabelen til false ved hjelp av end-metoden. Noen ganger har vi behov for å synkronisere to eller flere tråder. Det vil si at vi vil sikre oss at en tråd er ferdig med en oppgave før neste tråd begynner. Vi skal nå se på hvordan dette gjøres. Vi tenker oss følgende program: En kokk som legger mat på en tallerken og setter den fram på disken, lager en ny tallerken og setter på disken, osv., og en servitør som tar en tallerken og serverer maten, henter en ny tallerken og serverer, osv. De to jobber i litt ulikt tempo. Kokken kan både være raskere, men også tregere til å sette fram maten enn servitøren er til å hente den. Dette er en variant av et klassisk trådproblem, kalt produsent-konsument-problemet. Kokken vår er produsenten, og servitøren er konsumenten. Produsent og konsument kjøres i hver sin tråd. I tillegg har restauranten en egen tråd. Vi må hindre at to eller flere tråder samtidig skriver variabler de alle har adgang til. Hvis vi foran en metode skriver Java-ordet synchronized, vil alle slike synkroniserte metoder i den klassen være sperret, og alle tråder som seinere prøver å bruke en slik metode, må vente inntil den tråden som holder på med en av de synkroniserte metodene er ferdig. For ikke å gjøre programmet altfor omfattende jukser vi litt og lar tallerkenene være representert ved to tellere i Restaurant-klassen, en for antall ferdige tallerkener fra kokken, og en teller for antall serverte tallerkener. I tillegg til de to tallerkentellerne inneholder klassen fire synkroniserte metoder:

18.3 Samarbeid mellom tråder 341 en for å ta imot en tallerken fra kokken (øker antlaget-telleren med en) en for å servere en tallerken (øker antservert med en) en for å teste om servitøren er ferdig en for å teste om kokken er ferdig Det er nå to mulige feilsituasjoner: at servitøren prøver å servere en tallerken som ennå ikke er laget, og at kokken lager flere tallerkener enn det er behov for (vi tillater høyst tre tallerkener som ennå ikke er servert). Restaurant-klassen blir som følger: class Restaurant { int antbestilt ; int antlaget= 0, antservert = 0; // tallerkenretter Restaurant(int ant) { antbestilt = ant; public static void main(string[] args) { Restaurant rest; rest = new Restaurant(Integer.parseInt(args[0])); Kokk kokk = new Kokk(rest); kokk.start(); Servitor servitør = new Servitor(rest); servitør.start(); synchronized boolean kokkferdig () { return antlaget == antbestilt; synchronized boolean servitørferdig () { return antservert == antbestilt; synchronized void puttallerken() { // Kokketråden blir eier av låsen. while (antlaget - antservert > 2) { /* så lenge det er minst 2 tallerkener Javabok-2011.pdf 341 03.07.2011 12:01:37

342 18 Tråder * som ikke er servert, skal kokken vente. */ try { wait(); /* Kokketråden gir fra seg * låsen og sover til den * blir vekket */ catch (InterruptedException e) {return; // Kokketråden blir igjen eier av låsen. antlaget++; System.out.println("Kokken laget nr " + antlaget); notify(); /* Si ifra til servitøren. */ synchronized void gettallerken() { // Servitørtråden blir eier av låsen. while (antlaget == antservert) { /* så lenge kokken ikke har plassert * en ny tallerken. Dermed skal * servitøren vente. */ try { wait(); /* Servitørtråden gir fra seg * låsen og sover til den * blir vekket */ catch (InterruptedException e) {return; // Servitørtråden blir igjen eier av låsen. antservert++; System.out.println("Servitør serverer nr:" + antservert); notify(); /* si ifra til kokken. */ Kokken og servitøren skal henholdsvis produsere og konsumere det antall tallerkener vi oppgir på kommandolinja når vi starter programmet. Når kokken har produsert tallerken nr. 1, kan servitøren konsumere den. Så, når kokken Javabok-2011.pdf 342 03.07.2011 12:01:37

18.3 Samarbeid mellom tråder 343 har produsert neste tallerken, kan servitøren konsumere tallerken nr. 2, osv. Vi lar også gjerne kokken lage ferdig inntil 3 tallerkener før vi stopper kokken. De to klassene ser dermed slik ut: class Kokk extends Thread { Restaurant rest; Kokk(Restaurant rest) { this.rest = rest; while (!rest.kokkferdig()) { rest.puttallerken(); // lever tallerken try { sleep((long) (1000 * Math.random())); catch (InterruptedException e) {return; // Kokken er ferdig class Servitor extends Thread { Restaurant rest; Servitor(Restaurant rest) { this.rest = rest; while (!rest.servitørferdig()) { rest.gettallerken(); /* hent tallerken og * server */ try { sleep((long) (1000 * Math.random())); catch (InterruptedException e) {return; // Servitøren er ferdig Som du ser, lar vi kokken og servitøren vente mellom 0 og 1 sekund, tilfeldig valgt, før neste runde i while-løkka. En kjøring av programmet kan for eksempel resultere i følgende: Javabok-2011.pdf 343 03.07.2011 12:01:37

344 18 Tråder >java Restaurant 6 Kokken laget nr 1 Servitør serverer nr 1 Kokken laget nr 2 Kokken laget nr 3 Servitør serverer nr 2 Kokken laget nr 4 Kokken laget nr 5 Servitør serverer nr 3 Kokken laget nr 6 Servitør serverer nr 4 Servitør serverer nr 5 Servitør serverer nr 6 Fordi vi trekker tilfeldige ventetider, har en annen kjøring med samme antall tallerkener gitt: >java Restaurant 6 Kokken laget nr 1 Servitør serverer nr 1 Kokken laget nr 2 Servitør serverer nr 2 Kokken laget nr 3 Servitør serverer nr 3 Kokken laget nr 4 Kokken laget nr 5 Servitør serverer nr 4 Kokken laget nr 6 Servitør serverer nr 5 Servitør serverer nr 6 En advarsel til slutt. Programmering med tråder er ikke lett. Å lage slike programmer tilhører vanligvis hovedfagspensum. Hovedproblemet er at vi ikke kan stole på at setningene blir utført en etter en, slik de blir det i et vanlig program; en del av programmet vårt kan nemlig stoppes tilfeldig ett eller annet sted, og en annen del kan få utført noen av sine instruksjoner. En viktig grunn til å nevne dette i en begynnerbok i Java-programmering er at mange av metodene i Java-biblioteket starter tråder uten at det går klart fram av dokumentasjonen. Hvis man for eksempel programmerer grafiske

18.5 Oppgaver 345 grensesnitt med Swing, vil man få startet (minst) en ekstra tråd. Metoden paint() vil alltid kjøre på denne nye tråden. Hvis man vil unngå noen av problemene fra grafisk brukergrensesnitt-programmering, vil følgende regel være nyttig: Skriv ikke på (oppdater ikke) noen av variablene i programmet inne i paint(), men du kan godt lese alle typer av variabler i paint(). 18.4 Oppsummering Et program består av en eller flere tråder (programflyter), og alle tråder i et program har felles adresserom (ser de samme klassene med deres variabler). Metoder som kan bli nyttet av mer enn en tråd, må få Java-ordet synchronized foran deklarasjonen. Da sperres andre tråder fra å bruke noen av de metodene i klassen som er synkronisert (de må vente), hvis en slik metode allerede utføres av en av trådene. Et vanlig program har bare én tråd, men ved enten å lage en subklasse av Thread, implementere grensesnittet Runnable eller kalle noen av klassene i Java-biblioteket (og det er ikke dokumentert hvilke), kan vi få to eller flere tråder i programmet. En tråd som utføres, også vanlige programmer med bare en tråd, kan vente et visst antall millisekunder ved å kalle på Thread.sleep(millisek). Et brukergrensesnitt starter en egen tråd, og paint-metoden kjører på denne tråden. Program med flere tråder som ikke er riktig programmert, stopper enten helt opp (henger) eller gir gale resultater, eller begge deler. Det er vanskelig å programmere med tråder, og man må ha gode grunner til å gjøre det. 18.5 Oppgaver Oppgave 1 Utvid stoppeklokkeeksemplet til å kjøre to klokker samtidig i hver sin tråd. En tråd skriver ut en tekst hvert minutt, og en annen tråd skriver ut et tall hvert sekund.

346 18 Tråder Oppgave 2 Utvid Restaurant-programmet til å ha to objekter av klassen Kokk. Dette gjør du ved å kopiere fra de to kodelinjene i main som lager en kokk. Kjør dette programmet flere ganger og se om du kan observere feil oppførsel. (Hint: Prøv å kjøre programmet flere ganger med at du bare skal lage 1 tallerken.) Greier du a) å forklare de feilene du kan observere, og b) å rette feilene? Oppgave 3 Vanskelig: Utvid Restaurant-programmet slik at du samtidig har 5 kokker og 7 servitører (hver med et nummer som kommer med i utskriften). Hint: Du må bl.a. innføre flere tester ved kall på de metodene som allerede er definert for å få dette programmet riktig.