/** * Bolle-klassen */ public class Bolle {} // tom klasse?¨C 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(); } }