Föreläsning 7. Designmönstret Singleton. Designmönstret State. Trådar

Relevanta dokument
Trådar. Aktiva objekt

Föreläsning 11. Trådar

Föreläsning 11. Trådar Trådsäkerhet

Föreläsning 14. Trådar. Trådar Trådsäkerhet. Aktiva objekt. Motivering

Trådar och trådsäkerhet. Objekt-orienterad programmering och design Alex Gerdes, 2018

Trådar och trådsäkerhet. Objekt-orienterad programmering och design Alex Gerdes, 2016

9 Aktiva objekt och trådar

Concurrency Saker händer samtidigt. Process En instans av ett program

Trådar. Motivering. Många program måste kunna hålla på med flera saker samtidigt, till exempel. fleranvändarsystem.

Parallellism, återblick

Föreläsning 8 - del 2: Objektorienterad programmering - avancerat

Idag. Exempel, version 2. Exempel, version 3. Ett lite större exempel

Enkla variabler kontra referensvariabel

Tung bakgrundsaktivitet t.ex. Aktiva objekt t.ex. Animering, simulering. DD2385 Programutvecklingsteknik Några bilder till föreläsning 9 6/5 2013

Javas Exceptions. DD2385 Programutvecklingsteknik Fler bilder till föreläsning 7 23/ Kort om Javas Exceptions Trådar i Java

Objektorienterad Programkonstruktion. Föreläsning 2 2 nov 2016

Programmering med Java. Grunderna. Programspråket Java. Programmering med Java. Källkodsexempel. Java API-exempel In- och utmatning.

DI-institutionen Sid 1 av 6 Hans-Edy Mårtensson Sten Sundin

Chapter 4: Writing Classes/ Att skriva egna klasser.

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Lösningsförslag till tentamen för TDA540 Objektorienterad Programmering

2I1049 Föreläsning 5. Objektorientering. Objektorientering. Klasserna ordnas i en hierarki som motsvarar deras inbördes ordning

FÖRSLAG TILL LÖSNINGAR FÖR TENTAMEN I INTERNETPROGRAMMERING MED JAVA, 5p för SY , kl

Objektorienterad Programkonstruktion. Föreläsning dec 2015

Del A (obligatorisk för alla)

Kungliga Tekniska Högskolan Ämneskod 2D4134 Nada Tentamensdag maj - 19 Tentamen i Objektorientering och Java Skrivtid 5 h

JAVAUTVECKLING LEKTION 4

Lite om felhantering och Exceptions Mer om variabler och parametrar Fält (eng array) och klassen ArrayList.

Mer om klasser och objekt

Föreläsning 12. Föreläsning 12. Rörliga figurer Klassen Timer Undantag Något om applets. Rörliga appletsfigurer Klassen Timer Undantag

Objektorienterad Programkonstruktion, DD1346. Tentamen , kl

Subklasser och arv Inledning till grafik (JFrame och JPanel). Något om interface. Objektorienterad programvaruutveckling GU (DIT011) Subklasser

F8 - Arv. ID1004 Objektorienterad programmering Fredrik Kilander

Lösningsförslag övning 2.

Det finns en referensbok (Java) hos vakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Det finns en referensbok (Java) hos tentavakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Det finns en referensbok (Java) hos tentavakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Tentamen Nätverksprogrammering Lösningsförslag

Tentamen Nätverksprogrammering Lösningsförslag

TDA550 Objektorienterad programvaruutveckling IT, forts. kurs Övning vecka 2

public och private Obs: private inte skyddar mot access från andra objekt i samma klass.

F4. programmeringsteknik och Matlab

Java TRÅDAR OCH GRAFIK. FAdil galjić

Objektorienterad Programkonstruktion, DD1346. Tentamen , kl

DAT043 Objektorienterad Programmering

TENTAMEN OOP

LÖSNINGSFÖRSLAG Programmeringsteknik För Ing. - Java, 5p

Tentamen. DD2385 Programutvecklingsteknik vt 2013 Onsdagen den 22 maj 2013 kl Hjälpmedel: penna, suddgummi, linjal

Tentamen Nätverksprogrammering Lösningsförslag

Grundkurs i programmering, 6 hp (725G61) Dugga 2 tillfälle 2

1.1 Runnable och Thread

DIAGNOSTISKT PROV. Tid. Hjälpmedel. Antaganden. Rättning. Övrigt. Diagnostiskt Prov. Klockan Inga

Tentamen LÖSNINGSFÖRSLAG. c) Tilldelningen C x = new D() ger kompileringsfel eftersom klassen D är abstrakt.

Omtentamen för TDA540 Objektorienterad Programmering. Institutionen för Datavetenskap CTH HT-17, TDA540. Dag: , Tid:

Objektorienterad Programkonstruktion. Föreläsning 11 6 dec 2016

Kopiering av objekt i Java

Dagens program. Programmeringsteknik och Matlab. Objektorienterad programmering. Vad är vitsen med att ha både metoder och data i objekten?

Objektorienterad programmering E. Telefonboken, än en gång. Gränssnitt. Telefonboken med gränssnitt specificerat, del 1.

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Tentamen. 2D4135 vt 2005 Objektorienterad programmering, design och analys med Java Lördagen den 28 maj 2005 kl

Föreläsning 8: Exempel och problemlösning

Classes och Interfaces, Objects och References, Initialization

DAT043 - Föreläsning 7

Objektorienterad programmering i Java Undantag Sven-Olof Nyström Uppsala Universitet Skansholm: Kapitel 11

TENTAMEN OOP

Java: kort introduktion. Trådar. Något om mutex, Dekkers algoritm och monitorer. Javas ("inbyggda monitor") synchronized.

Två designmönster, MVC och Observer/Observable. Objektorienterad programvaruutveckling GU (DIT011)

Vad handlar kursen om? Algoritmer och datastrukturer. Vad handlar kursen om? Vad handlar kursen om?

Föreläsnings 9 - Exceptions, I/O

DUGGA: Objektorienterade applikationer. Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad.

Inkapsling tumregler. Åtkomstmodifikatorer, instantiering, referenser, identitet och ekvivalens, samt klassvariabler. public och private

LÖSNINGSFÖRSLAG

Instuderingsuppgifter läsvecka 6 - LÖSNINGAR

Lösningsförslag till omtentamen för TDA540 Objektorienterad Programmering

Lösningsförslag till tentamen för TDA540 Objektorienterad Programmering

Övning vecka 6. public void method2() { //code block C method3(); //code block D }//method2

Command line argumenter. Objektorienterad Programmering (TDDC77) Vad blir resultatet? Nu då? Ahmed Rezine. Hösttermin 2016

Objektorienterad Programmering (TDDC77)

Laboration 1 - Grunderna för OOP i Java

TDDC77 Objektorienterad Programmering

Övning 5. TDA550 - Objektorienterad programvaruutveckling, fk

Att skriva till och läsa från terminalfönstret

TDA550 - Objektorienterad programvaruutveckling, fk

Dagens text. Programmeringsteknik. Mer om Scanner-klassen. Dialogrutor (klassen JOptionPane) Bubbelsortering. Omslagsklasser.

Det finns en referensbok (Java) hos vakten som du får gå fram och läsa men inte ta tillbaka till bänken.

1 Comparator & Comparable

Objektorientering. Objekt och metoder. Objektorientering. Viktiga begrepp. Klass. Objekt. Deklarativ programmering

Synkronisering. Ordning och reda

DAT043 Objektorienterad programmering för D, DIT011 Objektorienterad programvaruutveckling för GU

Grundläggande programmering med C# 7,5 högskolepoäng

Variabler som hör till enskilda objekt. Deklareras på översta nivån i klassen och i regel som private.

Lösningsförslag till tentamen i OOP, HI1027 Fredag 21 oktober 2011

Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad. Skriv ditt idnummer på varje blad (så att vi inte slarvar bort dem).

Objektorienterad programutveckling, fk

Arv: Fordonsexempel. Arv. Arv: fordonsexempel (forts) Arv: Ett exempel. En klassdefinition class A extends B {... }

Tentamen. Lösningsförslag

EDAA20 Föreläsning Klassen ArrayList. Viktiga operationer på ArrayList. Generisk klass

Idag. statiska metoder och variabler. private/public/protected. final, abstrakta klasser, gränssnitt, delegering. wrapper classes

TENTAMEN OOP

Lösningar till Fiktiv Tentamen på kursen. 2D4135 Objektorienterad programmering, design och analys med Java vt2004. Teoridel

Transkript:

TDA550 Objektorienterad programmering, fortsättningskurs Föreläsning 7 Designmönstret Singleton Designmönstret State Trådar Objektorienterad programmering fk 1 Föreläsning 7

Singleton Pattern En singleton-klass är en klass som det endast får finnas en instans av och att denna instans är globalt åtkomlig. Singleton -instance: Singleton -Singleton() +getinstance(): Singleton Den globala instansen av klassen hålls som en privat klassvariabeln i klassen själv (variabeln instance i figuren ovan). Konstruktorn i klassen är privat! Användare erhåller instansen av klassen via metoden getinstance(). Första gången getinstance() anropas skapas instansen, sparas i instance och instance returneras. Existerande instansen när getinstance() anropas returneras instance. En singleton klass är i övrigt som en vanlig klass och kan självklart ha fler variabler och metoder. Objektorienterad programmering fk 2 Föreläsning 7

Singleton Pattern Singleton -instance: Singleton -Singleton() +getinstance(): Singleton public class Singleton { private static Singleton instance; // Other useful instance variables here private Singleton() { public static Singleton getinstance() { if (instance == null) { instance = new Singleton(); return instance; // Other useful methods here Objektorienterad programmering fk 3 Föreläsning 7

State Pattern Objekt har tillstånd och beteenden. Objekt ändrar sina tillstånd beroende på interna och externa händelser. Om ett objekt går igenom ett antal klart identifierbara tillstånd och objektets beteende påverkas signifikant av sitt tillstånd kan det vara lämpligt att använda designmönstret State. //state-dependent method //delegate to concrete state public void method2() { state.operation2(); Context -state: State operation1() method2() <<interface>> State operation1() operation2() ConcreteState1 operation1() operation2() ConcreteState2 operation1() operation2() ConcreteState3 operation1() operation2() State-mönstret kapslar in de individuella tillstånden tillsammans med den logik som används för att byta tillstånd. Istället för att direkt implementera beteendet för ett objekt i metoderna i klassen, så delegerar objektet vidare vad som skall göras till ett annat objekt (som är av en annan klass). Detta innebär att man dynamiskt kan omkonfigurera och byta ut beteendet hos objekt, det är som att objektet "byter klass". Vanligt arv är ju en statisk relation som inte kan förändras under runtime. Objektorienterad programmering fk 4 Föreläsning 7

Exempel på State-mönstret Antag att vi har en amfibiebil. När amfibiebilen körs på land driver motorn bakhjulen och när den körs i vatten driver motorn två propellrar. Styrningen sker både på land och i vatten med framhjulen. Låt oss säga vi vill ha följande operationer på amfibiebilen: prepareforwater() prepareforland() turnright() turnleft() byt tillstånd för att köras i vatten byt tillstånd för att köras på land sväng höger, samma påde på land och i vatten sväng vänster, samma påde på land och i vatten go() stop() kör, är olika beroende av om amfibiebilen är på land eller i vatten stanna, är olika beroende av om amfibiebilen är på land eller i vatten Objektorienterad programmering fk 5 Föreläsning 7

Design Amphicar -state: Conveyance turnleft() turnright() go() stop() prepareforwater() prepareforland() <<interface>> Conveyance moveforward() slowdown() //state-dependent method //delegate to concrete state public void stop() { state.slowdown(); Car +instance(): Conveyance moveforward() slowdown() Boat +instance(): Conveyance moveforward() slowdown() Observera att i denna design är klasserna Car och Boat singleton. Detta är inte nödvändigt, men har gjorts för att visa hur detta mönster kan används. public interface Conveyance { abstract public void moveforward(); abstract public void slowdown(); Objektorienterad programmering fk 6 Föreläsning 7

Exempel: Klasserna Car och Boat public class Car implements Conveyance { private static Conveyance instance = null; private Car(){; public static Conveyance instance() { if (instance == null) instance = new Car(); return instance; public void moveforward() { System.out.println("Forward power to rear wheels"); public void slowdown() { System.out.println("Apply breaks on each wheel"); public class Boat implements Conveyance { private static Conveyance instance = null; private Boat(){; public static Conveyance instance() { if (instance == null) instance = new Boat(); return instance; public void moveforward() { System.out.println("Forward power to propeller"); public void slowdown() { System.out.println("Reverse power to propeller"); Objektorienterad programmering fk 7 Föreläsning 7

Exempel: Klassen Amphicar public class Amphicar { private Conveyance state; public Amphicar() { state = Car.instance(); public Amphicar(Conveyance c) { state = c; public void go() { state.moveforward(); public void stop() { state.slowdown(); // Turning doesn't depend on the state //so it is implemented here. public void turnright() { System.out.println("Turn wheels right."); public void turnleft() { System.out.println("Turn wheels left."); public void prepareforwater() { state = Boat.instance(); public void prepareforland() { state = Car.instance(); Objektorienterad programmering fk 8 Föreläsning 7

Exempel: Testprogram public class Main { public static void main(string[] args) { Amphicar a = new Amphicar(); a.go(); a.turnright(); a.stop(); a.prepareforwater(); a.go(); a.turnright(); a.stop(); Testkörning: Forward power to rear wheels Turn wheels right. Apply breaks on each wheel Forward power to propeller Turn wheels right. Reverse power to propeller Objektorienterad programmering fk 9 Föreläsning 7

Aktiva objekt Det är välkänt från vardagslivet att saker händer samtidigt. Aktiva objekt gör saker på eget initiativ, medan passiva objekt endast gör saker när de blir ombedda. Det är viktigt att det underliggande systemet stöder parallellism så att man kan modellera verkligheten på ett bra sätt. Det är onaturligt att modellera parallellism som ett sekventiellt förlopp. I datorer med en processor simuleras parallellismen. task 1 task 2 task 3 task 1 task 2 task 3 Tre processer Äkta parallellism Tre processer Simulerad parallellism Objektorienterad programmering fk 10 Föreläsning 7

Motivering Många program måste kunna hålla på med flera saker samtidigt: bokningssystem av olika slag en webbserver som måste kunna leverera flera webbsidor samtidigt en grafisk applikation som ritar samtidigt som den arbetar med nästa bild ett grafiskt användargränssnitt som utför beräkningar och samtidigt är redo att ha dialog med användaren en webbläsare som börjar visa ett dokument innan hela dokumentet är nedladdat Denna typ av program kallas samverkande program (concurrent programs). Vi skall här endast ge en introduktion till programmering med samverkande program, för mer djupgående studier hänvisas till kursen Parallellprogrammering. Objektorienterad programmering fk 11 Föreläsning 7

Trådar I Java beskriver man aktiva objekt (och parallellism) med hjälp av standardklassen Thread. Aktiviteter som pågår samtidigt kallas därför i Java för trådar. objekt1 m0 m1 m2 objekt2 m5 m6 objekt3 m10 m11 m12 objekt5 m7 objekt4 m3 m8 m4 m9 Objektorienterad programmering fk 12 Föreläsning 7

Trådar I ett parallellt program beskrivs varje aktivitet som en instans av klassen Thread. Det tråden skall utföra definieras genom att överskugga metoden run(). public class SupporterThread extends Thread { private String team; public SupporterThread(String team) { this.team = team; public void run() { for(int i = 0; i <= 10; i = i + 1) System.out.print(team + " ") System.flush(); För att starta exekveringen av en tråd anropar man metoden start() (inte run()!!). public class SMFinal{ public static void main(string[] arg) { Thread ifkfan = new SupporterThread("IFK"); Thread aikfan = new SupporterThread("AIK"); ifkfan.start(); aikfan.start(); Utskriften kan t.ex. bli: IFK IFK IFK IFK IFK IFK AIK AIK AIK AIK IFK IFK IFK IFK AIK AIK AIK AIK AIK AIK Objektorienterad programmering fk 13 Föreläsning 7

Icke-deterministiskt beteende Sekventiella program säges vara deterministiska vilket betyder att: vilka operationer som utförs i programmet är en konsekvens av föregående operationer det är förutsägbart i vilken ordning operationerna i ett sekventiellt program kommer att utföras om ett program körs flera gånger med samma indata kommer samma resultat att erhållas varje gång Program med parallellism uppvisar ett icke-deterministiskt beteende: i vilken ordning operationerna sker mellan de olika programflödena vet vi inte två programkörningar med samma indata kan ge olika resultat Objektorienterad programmering fk 14 Föreläsning 7

Metoden sleep() En tråd kan temporärt avbryta sin exekvering med metoden sleep(), som är en klassmetod i klassen Thread. sleep() finns i följande två versioner: public static sleep(long mills) throws InterruptedException public static sleep(long mills, int nanos) throws InterruptedException Tiden som man vill avbryta trådens exekvering anges alltså i millisekunder respektive millisekunder och nanosekunder. Eftersom sleep() kan kasta en kontrollerad exceptionell händelse måste anropet av metoden ligga i ett try-catchblock. Objektorienterad programmering fk 15 Föreläsning 7

Exempel: SleepingSupporterThread Nedan har vi skrivit om föregående exempel på så sätt att vi låter tråden sova med ett slumpmässigt tidsintervall mellan 0 och 1 sekund mellan varje utskrift. Vi nyttjar också att klassen Thread har en konstruktor public Thread(String name) som ger tråden namnet name, samt att detta namn kan avläsas med metoden getname(). public class SleepingSupporter extends Thread { public SleepingSupporter(String team) { super(team); //Ger tråden ett namn public void run() { for(int i = 1; i <= 10; i = i + 1) { try { sleep((int)(math.random() * 1000)); catch(interruptedexception e) { System.out.println(i + " " + getname()); Objektorienterad programmering fk 16 Föreläsning 7

Exempel: fortsättning Vi skriver ett program som innehåller tre objekt av typen SleepingSupporterThread: public class CupFinal { public static void main(string[] arg) { Thread ifkfan = new SleepingSupporter("IFK"); Thread aikfan = new SleepingSupporter("AIK"); Thread hulligan = new SleepingSupporter( "Ut med domaren"); ifkfan.start(); aikfan.start(); hulligan.start(); De tre trådarnas utmatning sker i oförutsägbar ordning. En körning kan se ut enligt nedan: 1 AIK 1 IFK 1 Ut med domaren 2 IFK 3 IFK 2 AIK 3 AIK 2 Ut med domaren 4 AIK 4 IFK... Objektorienterad programmering fk 17 Föreläsning 7

Interfacet Runnable Eftersom Java inte tillåter multipla arv är det omöjligt för en klass som är subklass till Thread att ärva från någon annan klass. Aktiva objekt har många gånger behov av att ärva från andra klasser. Lösningen är att använda interfacet Runnable: public interface Runnable { public void run(); har endast en metod run(). varje klass som inplementerar Runnable måste implementera metoden run(). metoden run() i klassen som implementerar Runnable är utgångspunkten för exekveringen av en tråd. Objektorienterad programmering fk 18 Föreläsning 7

Interfacet Runnable Ett Runnable-objekt abstraherar begreppet ett jobb (t.ex. ett recept). Ett Thread-objekt abstraherar begreppet en arbetare (t.ex. en kock). Hur kan vi associera ett jobb med en arbetare? Genom att klassen Thread har en konstruktor public Thread(Runnable r) Konstruktorn skapar ett Thread-objekt som när det startas exekverar metoden run() i r. Exempel: Runnable recept =...; Thread kock = new Thread(recept) Objektorienterad programmering fk 19 Föreläsning 7

Exempel Runnable Vi skriver en klass Writer som har två instansvariabler text och intervall. När ett objekt av klassen Writer exekveras skall texten text skrivas ut gång på gång med ett tidsintervall av interval sekunder mellan utskrifterna. public class Writer implements Runnable { private String text; private long interval; public Writer(String text, long time) { this.text = text; interval = time * 1000; public void run() { while(!thread.interrupted()) { try { Thread.sleep(interval); catch (InterruptedException e) { break; System.out.print(text + " "); System.out.flush(); Objektorienterad programmering fk 20 Föreläsning 7

Exempel Runnable För att demonstrera hur flera objekt av klassen Writer kan exekvera parallellt ges nedan ett program som under en minut skriver ut "IFK" var 3:e sekund, "AIK" var 4:e sekund och "Ut med domaren" var 5:e sekund. public class TestWriter { public static void main(string[] arg){ Thread ifkfan = new Thread(new Writer("IFK", 3)); Thread aikfan = new Thread(new Writer("AIK", 4)); Thread hulligan = new Thread( new Writer("Ut med domaren", 5)); ifkfan.start(); aikfan.start(); hulligan.start(); try { Thread.sleep(60000); ifkfan.interrupt(); aikfan.interrupt(); hulligan.interrupt(); catch(interruptedexception e) { Utskriften från programmet blir: IFK AIK Ut med domaren IFK AIK IFK Ut med domaren AIK IFK Ut med domaren IFK AIK IFK Ut med domaren AIK IFK AIK IFK Ut med domaren IFK AIK Ut med domaren IFK AIK IFK Ut med domaren AIK IFK IFK Ut med domaren AIK IFK AIK Ut med domaren IFK AIK IFK Ut med domaren IFK AIK IFK Ut med domaren AIK IFK Objektorienterad programmering fk 21 Föreläsning 7

Vänta på att tråden skall avsluta metoden join() Vi utökar vår tidigare klass SMFinal enligt: public class SMFinal{ public static void main(string[] arg) { Thread ifkfan = new SupporterThread("IFK"); Thread aikfan = new SupporterThread("AIK"); ifkfan.start(); aikfan.start(); System.out.println("Storma plan!"); När stormas planen? För att vänta på att en tråd avslutas används metoden join(): public class SMFinal{ public static void main(string[] arg) { Thread ifkfan = new SupporterThread("IFK"); Thread aikfan = new SupporterThread("AIK"); ifkfan.start(); aikfan.start(); try { ifkfan.join(); aikfan.join(); catch (InterruptedException e) { System.out.println("Slutsignal! Storma plan!"); Objektorienterad programmering fk 22 Föreläsning 7

Bakgrundsjobb public class BackgroundJob extends Thread { private int maxsteps = 0; private long sum = 0; // Calculate sum = 1+2+3+... private long interval; public BackgroundJob(long interval, int maxsteps) { this.maxsteps = maxsteps; this.interval = interval; public void run() { int i = 1; while ( i <= maxsteps &&! Thread.interrupted() ) { try { Thread.sleep(interval); catch (InterruptedException e) { break; System.out.println("Background work... " + i++); sum += i; System.out.println("Background work finished"); public long getresult() { return sum; Objektorienterad programmering fk 23 Föreläsning 7

Bakgrundsjobb (fortsättning) public class Main { private BackgroundJob backgroundjob = new BackgroundJob(1000,10); public Main() { backgroundjob.start(); // Start background thread foregroundjob(); // Do foregroundjob in parallel public void foregroundjob() { int i = 0; while (i <= 20 &&! Thread.interrupted() ) { try { Thread.sleep(200); catch (InterruptedException e) { break; System.out.println("Foreground: " + i++); try { backgroundjob.join(); catch (InterruptedException e) { System.out.println("Background result: " + backgroundjob.getresult() ); System.out.println("Foreground work continues..."); public static void main(string[] arg) { Main m = new Main(); Objektorienterad programmering fk 24 Föreläsning 7

Trådsäkerhet Då ett objekt modifieras kan det inta ett antal tillfälliga tillstånd som inte är konsistenta (d.v.s. ogiltiga). Om en tråd avbryts under en modifikation av ett objekt, så kan det lämna objektet i ett ogiltigt tillstånd. En klass säges vara trådsäker om den garanterar konsistens för sina objekt, även om det finns multipla trådar närvarande. tråd 1 tråd 2 avariable = 123; avariable avariable = 45;????? Objektorienterad programmering fk 25 Föreläsning 7

Kritiska sektioner Kodsegment som har access till samma objekt från olika separata trådar utgör en s.k. kritisk sektion (eng: critical section), och måste synkroniseras på så sätt att endast en tråd i taget får tillgång till objektet, annars kan objektet hamna i ett inkonsistent tillstånd. Exempel: Antag att vi har en klass för att handha bankkonton enligt nedan: public class Account { private double balance;... public boolean withdraw(double amount) { if (amount <= balance) { balance = balance - amount; return true; else return false; public void deposite(double amount) { balance = balance + amount;... Objektorienterad programmering fk 26 Föreläsning 7

Inkonsistent tillstånd Antag vidare att balansen på ett konto är 100000 kronor och att två uttag görs samtidigt vardera på 100000 kronor. Följande kan hända: Balans Uttag 1 Uttag 2 100000 amount<= balance 100000 amount<= balance 100000 newbalance = balance - amount 100000 newbalance = balance - amount 0 balance = newbalance 0 balance = newbalance 0 return true 0 return true Ett inkonsistent tillstånd på kontot har inträffat!! Balansen borde vara -100000 men är 0. Objektorienterad programmering fk 27 Föreläsning 7

Synkronisering För att kontot inte skall hamna i ett inkonsistent tillstånd måste metoden withdraw synkroniseras, d.v.s. endast en tråd i taget skall kunna få tillgång till metoden. Java:s lösning för att åstadkomma synkronisering: varje objekt har ett singulärt lås. för att en tråd skall få tillträde till en kritisk sektion måste tråden först få tillgång till låset. att ha tillgång till låset innebär att ingen annan tråd kan ha tillgång till låset. låset återlämnas när tråden lämnar den kritiska sektionen. Allt detta görs automatiskt med konstruktionen synchronized. Programmerarens uppgift är att identifiera de kritiska sektionerna. Objektorienterad programmering fk 28 Föreläsning 7

Synkroniserad version av withdraw En synkroniserad version av withdraw får följande utseende: public class Account { private double balance;... public synchronized boolean withdraw( double amount) { if (amount <= balance) { balance = balance - amount; return true; else return false;... Objektorienterad programmering fk 29 Föreläsning 7

Konsistent tillstånd Om vi nu återigen antar att balansen på kontot är 100000 kronor och att två uttag görs samtidigt på 100000 kronor händer följande: Balans Uttag 1 Uttag 2 100000 amount<= balance 100000 newbalance = balance - amount 0 balance = newbalance 0 return true 0 amount<= balance 0 return false Objektorienterad programmering fk 30 Föreläsning 7

Ömsesidig uteslutning För att göra klassen Account trådsäker räcker det inte att enbart metoden withdraw är synkroniserad, utan även metoden deposite måste synkroniseras. Detta på grund av att båda metoderna konkurrerar om att förändra tillståndet på variabeln balance. public class Account { private double balance;... public synchronized boolean withdraw(double amount) { if (amount <= balance) { double newbalance = balance - amount; balance = newbalance; return true; else return false; public synchronized void deposite(double amount) { balance = balance + amount;... ac.withdraw stänger ute ytterligare en ac.withdraw ac.withdraw stänger ute ac.deposit ac.deposit stänger ute ytterligare en ac.deposit ac.deposit stänger ute ac.withdraw men ac1.withdraw stänger inte ute ac2.withdraw, etc. Objektorienterad programmering fk 31 Föreläsning 7

Låset ägs av tråden Låset ägs av tråden, vilket förhindrar att en tråd blir blockerad av ett lås som tråden redan har: public class ChainExample { public synchronized void methoda() { //do something methodb(); //do something more public synchronized void methodb() { //do something I och med att tråden är i besittning av låset när metoden methoda börjar exekvera och låset släpps först när exekveringen av metoden är klar är tråden i besittning av låset när den synkroniserade metoden methodb anropas. Objektorienterad programmering fk 32 Föreläsning 7

Synkronisering av satser (1) Om alla metoder är synkroniserade i ett objekt kan endast en tråd åt gången använda objektet. För lite synkronisering konflikter mellan trådar inkonsistens på grund av tillgång till samma resurs För mycket synkronisering trådarna får vänta på varandra, ingen parallellism Därför är det även möjligt att synkronisera enskilda satser med konstruktionen: synchronized (obj) { <statements> där obj är en godtycklig objektreferens. För att att kunna exekvera satserna i <statements> måste tråden äga låset till objektet obj. public static void metodx(int[] n) {... synchronized(n) { for (int = 0; i < n.length; i = i + 1) if (n[i] > 100) save(n[i]); //utförs... // objektet n är // låst för andra //trådar medan //dessa satser Objektorienterad programmering fk 33 Föreläsning 7

Synkronisering av satser (2) Om satser som berör en primitiv variabel skall synkroniseras associeras den primitiva variabeln med ett lås-objekt. public class PrimaryTypeSynchronization { private int valuea; private double valueb; private Object locka = new Object(); private Object lockb = new Object(); public void seta(int value) { synchronized(locka) { valuea = value; public double geta() { synchronized(locka) { return valuea; public void setb(double value) { synchronized(lockb) { valueb = value; public double getb() { synchronized(lockb) { return valueb; Objektorienterad programmering fk 34 Föreläsning 7

Samarbete mellan trådar Synkronisering handlar om uteslutning inte samarbete. Samarbete innebär: vänta: när en tråd inte kan fortsätta, så låt andra trådar fortsätta meddela: väck upp sovande trådar om det händer något som dessa kanske väntar på Metoden notifyall() signalerar till andra trådar att objektet ändrats Metoden wait() suspenderar tråden och öppnar låset för objektet andra trådar får möjlighet att exekvera synkroniserade metoder tråden väcks när någon tråd anropar notifyall för objektet Anm: Det finns även en metod notify(), men den bör inte användas. Objektorienterad programmering fk 35 Föreläsning 7

Producent-konsument exempel Vi skall titta på ett mycket enkelt exempel på samarbete mellan två trådar. Vi har en klass CubbyHole som har en instansvariabel content, vilken kan förändras med metoden put och som kan läsas av med metoden get. public class CubbyHole { private int content; public void put(int value) { content = value; public int get() { return content; Vi har vidare en producent som sätter nya värde på instansvariabeln och en konsument som avläser instansvariabeln. Vad vi vill åstadkomma är att konsumenten avläser instansvariabeln i samma takt som producenten förändrar dess värde. Objektorienterad programmering fk 36 Föreläsning 7

Producent public class Producer extends Thread { private CubbyHole cubbyhole; public Producer(CubbyHole c) { cubbyhole = c; public void run() { for(int i = 0; i < 10; i++) { cubbyhole.put(i); System.out.println("Producer put " + i); try { Thread.sleep((int) (Math.random()*100)); catch (InterruptedException e) { Objektorienterad programmering fk 37 Föreläsning 7

Konsument public class Consumer extends Thread { private CubbyHole cubbyhole; public Consumer(CubbyHole c) { cubbyhole = c; public void run() { int value = 0; for (int i = 0; i < 10; i++) { value = cubbyhole.get(); System.out.println("Consumer gets " + value); try { Thread.sleep((int) (Math.random() * 100)); catch (InterruptedException e) { Objektorienterad programmering fk 38 Föreläsning 7

Testprogram Vi skriver ett litet test program: public class ProducerConsumerTest { public static void main(string[] args) { CubbyHole c = new CubbyHole(); Producer p1 = new Producer(c); Consumer c1 = new Consumer(c); p1.start(); c1.start(); Exempel på utskrift från programmet: Producer put 0 Consumer gets 0 Consumer gets 0 Consumer gets 0 Producer put 1 Consumer gets 1 Producer put 2 Consumer gets 2 Producer put 3 Producer put 4 Consumer gets 4 Producer put 5 Consumer gets 5 Consumer gets 5 Producer put 6 Consumer gets 6 Producer put 7 Consumer gets 7 Producer put 8 Producer put 9 Objektorienterad programmering fk 39 Föreläsning 7

Problem 1. Producer och Consumer inverterar när de använder cubbyhole. Lösning: Synkronisera metoderna set och get i klassen CubbyHole 2. Producer kan vara snabbare än Consumer. Consumer gets 2 Producer put 3 Producer put 4 Consumer gets 4 3. Producer kan vara långsammare än Consumer. Producer put 5 Consumer gets 5 Consumer gets 5 Producer put 6 Objektorienterad programmering fk 40 Föreläsning 7

Ett första (och misslyckat) försök att lösa problemet public class CubbyHole { private int content; private boolean empty = true; public synchronized void put(int value) { while(!empty) { //vänta till empty blir true content = value; empty = false; public synchronized int get() { while(empty) { //vänta tills empty blir false empty = true; return content; Exempel på utskrift från programmet: Producer put 0 Consumer gets 0 Producer put 1 Consumer gets 1 Inget mer händer. Vi har fått deadlock! Objektorienterad programmering fk 41 Föreläsning 7

En korrekt lösning public class CubbyHole { private int content; private boolean empty = true; public synchronized void put(int value) { while(!empty) { try { wait(); //släpp låset och vänta på att väckas catch (InterruptedException e) { content = value; empty = false; notifyall(); //väck alla som väntar på låset public synchronized int get() { while(empty) { try { wait(); //släpp låset och vänta på att väckas catch (InterruptedException e) { empty = true; notifyall(); //väck alla som väntar på låset return content; Objektorienterad programmering fk 42 Föreläsning 7

Flera producenter och flera konsumenter Vanligt är att man har ett system med många producenter och många konsumenter. I ett sådant används en synkroniserad kö för att lagra de producerade enheterana. Producenter P P P P Synkroniserad kö Konsumenter C C C Objektorienterad programmering fk 43 Föreläsning 7

import java.util.arraylist; public class Queue { private ArrayList<String> queue = new ArrayList<String>(); public int size() { return queue.size(); public synchronized void put(string obj) { queue.add(obj); notify(); public synchronized String take() { while (queue.isempty()) { try { wait(); catch (InterruptedException e) { return null; String obj = queue.get(0); queue.remove(0); return obj; Objektorienterad programmering fk 44 Föreläsning 7

import java.util.arraylist; public class JobShop { private Queue helpdeskqueue = new Queue(); private ArrayList<Thread> threads = new ArrayList<Thread>(); public JobShop() throws InterruptedException { createandstartthreads(); Thread.sleep(20000); stopthreads(); System.out.println("Jobs left in queue: " + helpdeskqueue.size()); System.exit(0); public void createandstartthreads() { threads.add( new Producer("Lamm",6237,helpDeskQueue)); threads.add( new Producer("Alto",2846,helpDeskQueue)); threads.add( new Producer("Holm",1239,helpDeskQueue)); threads.add(new Consumer("Erik",982,helpDeskQueue)); threads.add(new Consumer("Mikael",1654,helpDeskQueue)); for ( Thread t : threads ) t.start(); public void stopthreads() { for ( Thread t : threads ) t.interrupt(); public static void main (String[] arg) throws InterruptedException { JobShop j = new JobShop(); Objektorienterad programmering fk 45 Föreläsning 7

public class Producer extends Thread { private String name; private long interval; private Queue queue; private int nr = 0; public Producer(String name, long interval, Queue queue) { this.name = name; this. interval = interval; this.queue = queue; public void run() { while (!Thread.interrupted()) { try { Thread.sleep(interval); catch (InterruptedException e ) { break; queue.put(name + ": " + nr++); Objektorienterad programmering fk 46 Föreläsning 7

public class Consumer extends Thread { private String name; private long interval; private Queue queue; public Consumer(String name, long interval, Queue queue) { this.name = name; this.interval = interval; this.queue = queue; public void run() { while (!Thread.interrupted()) { try { Thread.sleep(interval); catch (InterruptedException e ) { break; System.out.println(name + " received job from " + queue.take()); Objektorienterad programmering fk 47 Föreläsning 7

Avbrott av trådar interrupt() sätter avbrottsflaggan för denna tråd. Det är (nästa) upp till tråden själv att reagera på denna flagga. Om tråden är blockerad på grund av ett anrop av metoderna wait(), sleep() eller join() kommer dessa att terminera och ett InterruptedException att kastas. Thread.interrupted() kollar och återställer avbrottsflaggan för aktuell tråd Thread1: thread2.interrupt(); Thread2: public void run() { try { while (!Thread.interrupted()) { //gör denna trådens job //inklusive något sleep(), wait() eller join() catch (InterruptedException e) { Objektorienterad programmering fk 48 Föreläsning 7