/** * Bolle-klassen */ public class Bolle {} // tom klasse – finnes kun for å kunne opprette boller /** * Bolleland-klassen */ import java.util.ArrayDeque; // en klasse som implementerer Queue import java.util.Queue; // et interface public class Bolleland { private Queue stativ = new ArrayDeque(); // LIFO-kø public void leggTilBolle(Bolle bolle) { stativ.add(bolle); } // legger til en bolle i stativet (slutten av køen) public Bolle selgBolle() { return stativ.remove(); } // fjerner en bolle fra stativet (starten av køen) public boolean tomtForBoller() { return stativ.isEmpty(); } // sjekker om stativet er tomt for boller } /** * Monitor-klassen */ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Monitor { private Lock laas = new ReentrantLock(); // en lås for å sikre kritiske regioner private Condition ikkeTomt = laas.newCondition(); // en tilstand for å holde styr på om stativet ikke er tomt private Bolleland bolleland; public Monitor(Bolleland bolleland) { this.bolleland = bolleland; } // produserende metode public void leggTilBolle(Bolle bolle) { laas.lock(); // låser før den kritiske regionen try { bolleland.leggTilBolle(bolle); ikkeTomt.signalAll(); // gir signal om at ikkeTomt-tilstanden har endret seg } finally { laas.unlock(); } // husk å låse opp i finally! Det som står i finally skjer uansett } // konsumerende metode // ikkeTomt.await() kan kaste en InterruptedException, så vi kaster den videre til kallstedet public Bolle selgBolle() throws InterruptedException { laas.lock(); try { while(tomtForBoller()) // hvis det er tomt for boller { ikkeTomt.await(); } // venter på at ikkeTomt-tilstanden skal endre seg, gir fra seg låsen midlertidig return bolleland.selgBolle(); } finally { laas.unlock(); } } public boolean tomtForBoller() { laas.lock(); try { return bolleland.tomtForBoller(); } finally { laas.unlock(); } } } /** * Baker-klassen: en produsent */ public class Baker implements Runnable { private final int ANTALL_PER_BRETT = 6; // konstant for antall boller per brett private final int SEKUNDER = 6000; // konstant for antall sekunder til sleep-metoden private boolean paaJobb = true; // true hvis bakeren er på jobb private Monitor monitor; public Baker(Monitor monitor) { this.monitor = monitor; } public void run() { try { while (paaJobb && !Thread.interrupted()) // går så lenge bakeren er på jobb og tråden ikke er avbrutt { for (int i = 0; i < ANTALL_PER_BRETT; i ++) // legger til et brett med boller { monitor.leggTilBolle(new Bolle()); } System.out.println("Bakte " + ANTALL_PER_BRETT + " boller"); Thread.sleep(SEKUNDER); // kan kaste en InterruptedException, så putter while-løkken i en try-blokk } System.out.println("Bakeren er ferdig på jobb!"); // hvis tråden er avbrutt etter sleep og før while-betingelsen sjekkes } catch (InterruptedException e) { System.err.println("Bakeren er ferdig på jobb!"); } // hvis det kalles interrupt() på tråden mens den er sovende } } /** * Kundebase-klassen: en konsument */ public class Kundebase implements Runnable { private final int SEKUNDER = 500; // konstant for antall sekunder til sleep-metoden private boolean lystPaaBolle = true; // så lenge kundene har lyst på bolle private Monitor monitor; public Kundebase(Monitor monitor) { this.monitor = monitor; } public void run() { try { while (lystPaaBolle && !Thread.interrupted()) // går så lenge kundene har lyst på bolle og tråden ikke er avbrutt { monitor.selgBolle(); System.out.println("Kjøpte en bolle"); Thread.sleep(SEKUNDER); // kan kaste en InterruptedException, så putter while-løkken i en try-blokk } System.out.println("Kundebasen får ikke kjøpt flere boller."); // hvis tråden er avbrutt etter sleep og før while-betingelsen sjekkes } catch (InterruptedException e) { System.err.println("Kundebasen får ikke kjøpt flere boller."); } // hvis det kalles interrupt() på tråden mens den er sovende } } /** * Hovedprogrammet */ public class Hoved { public static void main(String[] args) throws InterruptedException { Bolleland bolleland = new Bolleland(); Monitor monitor = new Monitor(bolleland); Baker cecilie = new Baker(monitor); // et Runnable-objekt av typen Baker Thread arbeider = new Thread(cecilie); // sender inn et Runnable-objekt til Thread-konstruktøren arbeider.start(); // start-metoden i Thread kaller run-metoden i Baker Kundebase kundebase = new Kundebase(monitor); Thread utsalg = new Thread(kundebase); utsalg.start(); int arbeidsdag = 30000; // 30 sekunder Thread.sleep(arbeidsdag); // lar bakeren produsere og kundene konsumere en arbeidsdag // stenger Bolleland System.out.println("Bolleland er nå stengt."); // trådene får beskjed om å avbryte arbeider.interrupt(); utsalg.interrupt(); } }