import java.util.HashMap; import java.util.HashSet; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Spinneri { // vanligvis en separat monitor // dette objektet skal trådene samarbeide om public String navn; public HashMap materialer = new HashMap<>(); public int antallNoester = 0; public Lock laas = new ReentrantLock(); // én lås til hele klassen, dvs. at kun én tråd kan utføre en oppgave i en kritisk region til enhver tid // conditions som jobber på den samme låsen public Condition plassTilMerMohair = laas.newCondition(); public Condition plassTilMerSilke = laas.newCondition(); public Condition nokMaterialer = laas.newCondition(); public boolean ferdig = false; public final int ANTALL_NOESTER; public Spinneri(String navn, HashSet garntyper, int ANTALL_NOESTER) { this.navn = navn; this.ANTALL_NOESTER = ANTALL_NOESTER; for (String type : garntyper) { materialer.put(type, 0); } } public void importerMohair() { laas.lock(); // trådene venter her når én tråd har gått inn i metoden. Denne tråden "eier" da låsen try { // vi importerer 100 gram mohair hver gang og har plass til 1000 while (!ferdig && (materialer.get("Mohair") + 100) > 1000) { try { // hvis en tråd må vente her, kommer flere inn og venter her sammen plassTilMerMohair.await(); // Når en annen metode signaliserer at det nå er plass til mer mohair, vil tråden som vekkes prøve å ta over låsen og sjekke betingelsen i while-løkka på nytt før den evt. går videre og utfører resten av koden i metoden } catch (InterruptedException e) { System.out.println("Tråden ble avbrutt"); } } // når vi er ute her, vil én tråd gå videre if (!ferdig) { materialer.put("Mohair", materialer.get("Mohair") + 100); if (materialer.get("Silke") >= 7) { nokMaterialer.signalAll(); // gir beskjed til alle andre tråder som venter på nokMaterialer } } } finally { laas.unlock(); // unngår deadlocks, dvs. at en metode aldri blir låst opp igjen mens vi har ventende tråder //Etter at låsen er åpnet, vil alle de oppdaterte variablene (tilstanden i programmet) bli synlige for de andre trådene } } public void importerSilke() { laas.lock(); // trådene venter her når én tråd har gått inn i metoden try { // vi importerer 50 gram silke hver gang, og har plass til 750 while (!ferdig && (materialer.get("Silke") + 50) > 750) { try { // hvis en tråd må vente her, kommer flere inn og venter her sammen plassTilMerSilke.await(); } catch (InterruptedException e) { System.out.println("Tråden ble avbrutt"); } } // når vi er ute her, vil én tråd gå videre if (!ferdig) { materialer.put("Silke", materialer.get("Silke") + 50); if (materialer.get("Mohair") >= 18) { nokMaterialer.signalAll(); // gir beskjed til alle andre tråder som venter på nokMaterialer // signalAll() øker robustheten sammenlignet med signal(), som kun vekker én tråd } } } finally { laas.unlock(); // unngår deadlocks } } public void spinnSilkMohair() { laas.lock(); try { // Med en while-løkke får vi at trådene venter aktivt på å utføre oppgaven sin while (!ferdig && (materialer.get("Mohair") < 18 || materialer.get("Silke") < 7)) { try { nokMaterialer.await(); // hvis en tråd må vente her, slippes låsen, og flere tråder kan komme og vente her sammen med den // når låsen slippes kan en annen tråd bruke den i en annen metode, hvilken tråd det blir avhenger av trådprioritet, "fairness policy" og operativsystemet } catch (InterruptedException e) { System.out.println("Tråden ble avbrutt"); } } // sjekker om vi ikke er ferdige for å slippe å utføre mer hvis vi er det if (!ferdig) { materialer.put("Mohair", materialer.get("Mohair") - 18); materialer.put("Silke", materialer.get("Silke") - 7); antallNoester++; if (antallNoester >= ANTALL_NOESTER) { ferdig = true; } // vi må huske å signalisere dersom vi nå har nok plass til mer materialer if ((materialer.get("Mohair") + 100) <= 1000) { plassTilMerMohair.signalAll(); } if ((materialer.get("Silke") + 50) <= 750) { plassTilMerSilke.signalAll(); } } } finally { laas.unlock(); } } public int antallNoester() { laas.lock(); try { return antallNoester; } finally { laas.unlock(); } } public boolean kjoepGarn() { laas.lock(); try { if (antallNoester >= 8) { // sjekker om vi har nok garn til en Kumulus Bluse, dette tallet kunne vi evt. sendt med som paramter til metoden (det hadde gjort den bedre) antallNoester -= 8; // antall nøster minker return true; } return false; // husk å returnere inni try-blokka } finally { laas.unlock(); } } }