package debuggees; /** * jBixbe debuggee: deals with the "smoker problem". * * Three smokers sit around a table in a pub and are served by a waitress. * In order to smoke a smoker needs paper, tobacco and matches and every smoker * owns plenty of one of the three items. The waitress lays two items on the * table and every smoker grabs at his missing items. * Note, normally a deadlock would appear but we avoid this by the fact * that the waitress cyclically brings new items. * * @author ds-emedia */ public class ThePub { private Table table; private Waitress waitress; private Smoker smokerWithPaper; private Smoker smokerWithMatches; private Smoker smokerWithTobacco; public ThePub() { table = new Table(); smokerWithPaper = new SmokerWithPaper(table); smokerWithPaper.start(); smokerWithMatches = new SmokerWithMatches(table); smokerWithMatches.start(); smokerWithTobacco = new SmokerWithTobacco(table); smokerWithTobacco.start(); waitress = new Waitress(table); waitress.start(); } public static void main(String[] args) { new ThePub(); } } class Table { boolean paper; boolean matches; boolean tobacco; synchronized void putDownPaper() { paper = true; this.notifyAll(); } synchronized void putDownMatches() { matches = true; this.notifyAll(); } synchronized void putDownTobacco() { tobacco = true; this.notifyAll(); } synchronized void takePaper() throws InterruptedException { while (!paper) { this.wait(); } paper = false; } synchronized void takeMatches() throws InterruptedException { while (!matches) { this.wait(); } matches = false; } synchronized void takeTobacco() throws InterruptedException { while (!tobacco) { this.wait(); } tobacco = false; } } class Smoker extends Thread { void smoke() throws InterruptedException { sleep(500); } } class SmokerWithPaper extends Smoker { private Table table; SmokerWithPaper(Table table) { this.table = table; setName("Smoker with paper"); } public void run() { while (true) { try { table.takeMatches(); table.takeTobacco(); smoke(); } catch (InterruptedException e) { /* ignore */ } } } } class SmokerWithMatches extends Smoker { private Table table; SmokerWithMatches(Table table) { this.table = table; setName("Smoker with matches"); } public void run() { while (true) { try { table.takeTobacco(); table.takePaper(); smoke(); } catch (InterruptedException e) { /* ignore */ } } } } class SmokerWithTobacco extends Smoker { private Table table; SmokerWithTobacco(Table table) { this.table = table; setName("Smoker with tobacco"); } public void run() { while (true) { try { table.takeMatches(); table.takePaper(); smoke(); } catch (InterruptedException e) { /* ignore */ } } } } class Waitress extends Thread { Table table; Waitress(Table table) { super("Waitress"); this.table = table; } void bringPaperAndTobacco() { table.putDownPaper(); table.putDownTobacco(); } void bringPaperAndMatches() { table.putDownPaper(); table.putDownMatches(); } void bringMatchesAndTobacco() { table.putDownMatches(); table.putDownTobacco(); } public void run() { while (true) { int item = (int) (Math.random() * 10); if (item <= 3) { bringPaperAndTobacco(); } else if (item <= 7) { bringPaperAndMatches(); } else { bringMatchesAndTobacco(); } try { sleep(2000); } catch (InterruptedException e) { /* ignore */ } } } }