Motivering Uppsala Universitet 21 april 2005 Många program måste kunna hålla på med flera saker samtidigt, till exempel fleranvändarsystem en webserver som måste kunna leverera flera websidor samtidigt ett grafiskt system som ritar samtidigt som det arbetar med nästa bild ett system som reagerar på input samtidigt som det utför en beräkning Objectorienterad programmering Sida 1 Objectorienterad programmering Sida 3 Dagens ämnen Timers Synkronisering Buffrad kommunikation Producent/Konsument-exempel Hålla på med flera saker... en browser som kan börja visa dokumentet innan hela dokumentet är nerladdat ett program som kontrollerar olika delar av en maskin ett program som övervakar olika delar av ett system Det är inte nödvändigt att använda trådar, men ofta lättare. Objectorienterad programmering Sida 2 Objectorienterad programmering Sida 4
Aktiva objekt Aktiva objekt: objekt som själva kan initera skeenden. I Java finns det två sätt att beskriva aktiva objekt; javax.swing.timer kan användas för att kontrollera en grupp av aktiva objekt, om de bara behöver arbeta i korta moment. (Det finns även en liknande klass, java.util.timer.) med hjälp av trådar java.lang.thread kan man hantera objekt som arbetar i längre moment (eller kontinuerligt). Enkelt exempel testkörning svenolof@hamberg$ svenolof@hamberg$ javac.java svenolof@hamberg$ java -Djava.compiler=NONE ^C Objectorienterad programmering Sida 5 Objectorienterad programmering Sida 7 javax.swing.timer: Exempel public class implements ActionListener { public () { javax.swing.timer tim = new javax.swing.timer(1000, this); tim.start(); public void actionperformed (ActionEvent e) { System.out.println(""); public static void main (String [] arg) { h = new (); for (int i = 0; i<integer.max_value; i++) { new Timer(m, l) start() stop() restart() setdelay() setrepeats(false) Skapa en timer som genererar en händelse var mte millisekund, med l som lyssnare. Starta timern. Stanna timern. Återstarta. Ändra intervallet mellan händelser. Bara en händelse genereras. Objectorienterad programmering Sida 6 Objectorienterad programmering Sida 8
Digitalklocka (från Skansholm) public class DigitalKlocka extends JLabel implements ActionListener { private DateFormat df = DateFormat.getTimeInstance(); public DigitalKlocka () { sethorizontalalignment(jlabel.center); setopaque (true); setbackground(color.white); setfont(new Font("SansSerif", Font.BOLD, 24)); javax.swing.timer tim = new javax.swing.timer(1000, this); tim.start(); public class KlockDemo extends JFrame { private DigitalKlocka k1 = new DigitalKlocka(); private DigitalKlocka k2 = new DigitalKlocka("EST"); public static void main(string[] args) { KlockDemo kd = new KlockDemo(); Objectorienterad programmering Sida 9 Objectorienterad programmering Sida 11 public DigitalKlocka(String zon) { this(); df.settimezone(timezone.gettimezone(zon)); public void actionperformed(actionevent e) { settext (df.format (new Date())); public KlockDemo () { Container c = getcontentpane(); JLabel l1 = new JLabel("Lokal tid", JLabel.CENTER); JLabel l2 = new JLabel("New York", JLabel.CENTER); l1.setfont(new Font("Serif", Font.BOLD, 18)); l2.setfont(new Font("Serif", Font.BOLD, 18)); c.setlayout(new GridLayout(2,2,5,5)); c.add(k1); c.add(k2); c.add(l1); c.add(l2); setsize(500, 250); setvisible(true); setdefaultcloseoperation(exit_on_close); Objectorienterad programmering Sida 10 Objectorienterad programmering Sida 12
och processer Vad är en tråd? En ensam tråd liknar ett vanligt sekvensiellt program men när vi har flera trådar blir det intressant. Exempel: HotJava, en web-browser man kan scrolla en sida medan den laddar ner nånting stort I verkligheten kan flera saker pågå samtidigt, så varför inte i en dator?... är billigare används om man vill låta en applikation hålla på med flera saker samtidigt. Ibland används begreppet lättviktsprocess. Det är samma sak. Implementationer av Java brukar använda operativsystemets trådar. Objectorienterad programmering Sida 13 Objectorienterad programmering Sida 15 I alla moderna operativsystem finns processer och trådar Processer är dyra, har eget minnesskydd används om flera användare kör samtidigt... Schemaläggning (scheduling) Cooperative scheduling Tråden körs tills den frivilligt ger upp kontrollen. Preemptive scheduling Byte mellan trådar sker automatiskt....eller om en användare kör flera program Tex Windows 98 använder cooperatice scheduling om en process kraschar ska andra processer inte påverkas Alla moderna OS använder preemptimptive scheduling Objectorienterad programmering Sida 14 Objectorienterad programmering Sida 16
. Ett enkelt exempel class SimpleThread extends Thread { public SimpleThread(String str) { super(str); public void run() { for (int i = 0; i < 10; i++) { System.out.println(i + " " + getname()); try { sleep((long)(math.random() * 1000)); catch (InterruptedException e) { System.out.println("DONE! " + getname()); public class TwoThreadsDemo { public static void main (String[] args) { new SimpleThread("Jamaica").start(); new SimpleThread("Fiji").start(); Objectorienterad programmering Sida 17 Objectorienterad programmering Sida 19 svenolof@harpo$ svenolof@harpo$ javac TwoThreadsDemo.java svenolof@harpo$ java TwoThreadsDemo 0 Jamaica 0 Fiji 1 Fiji 2 Fiji 1 Jamaica 2 Jamaica 3 Jamaica [...] 7 Jamaica 9 Fiji 8 Jamaica 9 Jamaica DONE! Fiji DONE! Jamaica svenolof@harpo$ Objectorienterad programmering Sida 18 Objectorienterad programmering Sida 20
Viktiga metoder Java.lang.thread start() Börja exekvering av nyskapad tråd sleep() Avbryt exekvering av tråd. Under den angivna tiden sover tråden yield() Ge en annan tråd möjlighet att köra Exempel: Primes.java En tråd beräknar primtal, en annan skriver ut det senast beräknade. Synkronisering Exempel: En enkel klass Konto: class Konto { private int saldo;.. public void transaktion( int belopp ) { saldo = saldo + belopp;.. Objectorienterad programmering Sida 21 Objectorienterad programmering Sida 23 Alternativt sätt att skapa och köra trådar I stället för att från klassen Thread, låt klassen K implementera interfacet Runnable En metod: run() K k = new K(); Thread t = new Thread(k); t.start(); Synkronisering (forts) Ett scenario med trådarna bankomat och girering. 1. Tråden bankomat anropar transaktion och har just beräknat saldo+belopp när den avbryts. 2. Tråden girering anropar transaktion, lägger till en summa och hinner ändra saldo 3. Tråden bankomat väcks och ger saldo sitt värde (ursprungligt saldo minus det uttagna beloppet). Objectorienterad programmering Sida 22 Objectorienterad programmering Sida 24
Synkronisering (forts) Efter dessa transaktioner : Saldot har minskat med det uttagna beloppet De insatta pengarna är borta (eftersom tråden girering var snabbare än tråden bankomat). För att eliminera risken att sådant här ska hända kan man deklarera metoder synchronized (som låser objektet) Metoden transaction skulle alltså deklareras synchronized public void transaktion(int belopp) { public class CubbyHole <T>{ private T contents; private boolean available = false; public synchronized T get() { while (available == false) { try { wait(); catch (InterruptedException e) { available = false; notifyall(); return contents; Objectorienterad programmering Sida 25 Objectorienterad programmering Sida 27 Hur kommunicerar två trådar? Enkel lösning: Ett objekt som båda kan se och uppdatera. Men hur upptäcker en process att ett objekt har uppdaterats? I klassen Object finns de tre metoderna wait() vänta till någon blir väckt, öppna låset notify() väck en väntande tråd notifyall() väck alla väntande trådar public synchronized void put(t value) { while (available == true) { try { wait(); catch (InterruptedException e) { contents = value; available = true; notifyall(); Objectorienterad programmering Sida 26 Objectorienterad programmering Sida 28
Producer public class Producer extends Thread { private CubbyHole<Integer> cubbyhole; private int number; public Producer(CubbyHole<Integer> c, int number) { cubbyhole = c; this.number = number; Consumer public class Consumer extends Thread { private CubbyHole<Integer> cubbyhole; private int number; public Consumer(CubbyHole<Integer> c, int number) { cubbyhole = c; this.number = number; Objectorienterad programmering Sida 29 Objectorienterad programmering Sida 31 Producer (forts) public void run() { for (int i = 0; i < 10; i++) { cubbyhole.put(i + this.number*10); System.out.println("Producer #" + this.number + " put: " + (i + this.number*10)); try { sleep((int)(math.random() * 100)); catch (InterruptedException e) { Consumer (forts) public void run() { int value = 0; for (int i = 0; i < 10; i++) { value = cubbyhole.get(); System.out.println("Consumer #" + this.number + " got: " + value); try { sleep((int)(math.random() * 50)); catch (InterruptedException e) { Objectorienterad programmering Sida 30 Objectorienterad programmering Sida 32
ProducerConsumerTest public class ProducerConsumerTest { public static void main(string[] args) { CubbyHole<Integer> c = new CubbyHole<Integer>(); Producer p1 = new Producer(c, 1); Producer p2 = new Producer(c, 2); Producer p3 = new Producer(c, 3); Consumer c1 = new Consumer(c, 1); Consumer c2 = new Consumer(c, 2); p1.start(); p2.start(); p3.start(); c1.start(); c2.start(); Producer2: Använd Runnable class Producer2 implements Runnable { [...] private Thread t = null; public Producer2(CubbyHole<Integer> c, int number) { [...] this.t = new Thread(this); public void start() { t.start(); public void run() {... Objectorienterad programmering Sida 33 Objectorienterad programmering Sida 35 svenolof@harpo$ java5 ProducerConsumerTest Consumer #2 got: 10 Producer #3 put: 30 Consumer #1 got: 20 Producer #2 put: 20 Producer #1 put: 10 Consumer #1 got: 30 Producer #3 put: 31 Consumer #2 got: 21 Producer #2 put: 21 Consumer #1 got: 31 Producer #3 put: 32 Consumer #2 got: 32 Producer #1 put: 11 Consumer #1 got: 11 Producer #3 put: 33 Consumer #2 got: 33 Producer #2 put: 22 Consumer #1 got: 22 Producer #3 put: 34 Consumer #2 got: 34 Producer #1 put: 12 [...] Cubbyhole: testkörning Köer Ett gränssnitt: BlockingQueue Implementerande klasser LinkedBlockingQueue och ArrayBlockingQueue LBQ är obegränsad; ABQ har en maxstorlek (som anges i konstruktorn) Objectorienterad programmering Sida 34 Objectorienterad programmering Sida 36
Problem med trådar Köer, metoder void put(e) Sätt in e sist i kön <T>take() ta ut första elementet <T>poll() första elementet om det finns, annars null <T>poll(n,u) med timeout Producer-consumer exempel, med BlockingQueue Java använder normalt operativsystemets trådar. Tyvärr slår skillnader mellan olika OS igenom i beteendet hos olika trådade program. Detta innebär att man inte alltid kan flytta trådade program mellan maskiner. Om man glömmer att synkronisera kan man få problem med tidsberoenden (race conditions). Om man synkroniserar för mycket kan programmet hänga sig, till exempel om två processer har låst varsitt objekt som den andra processen behöver (deadlock). Objectorienterad programmering Sida 37 Objectorienterad programmering Sida 39, fler exempel PipeTest.java Kommunikation med en ström. Balls.java Ett mellanspel om dubbelbuffring Problem med trådar (forts) Synkronisering är en ganska dyr operation. är en knapp resurs en modern dator klarar några tusen. Main2.java Kontrollera ett objekt i rörelse. Att programmera med nära samverkande trådar är krångligt pga oförutsägbarhet i schedulering etc. Objectorienterad programmering Sida 38 Objectorienterad programmering Sida 40
: Några råd Låt multitrådade program följa enkla modeller, till exempel med buffrad kommunikation eller som den multitrådade servern i nästa föreläsning. Undvik situationer där många trådar läser och skriver samma objekt. Låt inte antalet trådar växa obegränsat. Objectorienterad programmering Sida 41 Sammanfattning Två sätt att programmera aktiva objekt. Timers relativt enkelt men inte så kraftfullt. kraftfullare men det finns många fallgropar. Objectorienterad programmering Sida 42