diff --git a/src/main/java/usherbrooke/ift630/App.java b/src/main/java/usherbrooke/ift630/App.java index cc64ca9..ca282c2 100644 --- a/src/main/java/usherbrooke/ift630/App.java +++ b/src/main/java/usherbrooke/ift630/App.java @@ -13,22 +13,24 @@ public class App { static private int numStopPerBus = 8; static private int numStops = numBusses * numStopPerBus; static private int numPassengersPerBus = 10; - static private int numPassengersPerStop = 3; + static private int numPassengersPerStop = 3; static private int numPassengers = numPassengersPerStop * numStops; static private int numThreadsBus = 5; static private int numThreadsStop = 2; - static private int timeBetweenStops = 5; + static private int timeBetweenStops = 5; static private int timeEmbark = 2; - public static void main(String[] args) { - ExecutorService threadsBus = Executors.newFixedThreadPool(numThreadsBus); - ExecutorService threadsStop = Executors.newFixedThreadPool(numThreadsStop); - ArrayList stops = new ArrayList(); - ArrayList busses = new ArrayList(); - ArrayList passengers = new ArrayList(); - BlockingQueue blockingQueue = new LinkedBlockingQueue(); + public static void main(String[] args) { + ExecutorService threadsBus = Executors.newFixedThreadPool(numThreadsBus); + ExecutorService threadsStop = Executors.newFixedThreadPool(numThreadsStop); + ExecutorService threadsPassenger = Executors.newFixedThreadPool(1); // doesnt need more! future balance + // themselfes out. + ArrayList stops = new ArrayList(); + ArrayList busses = new ArrayList(); + ArrayList passengers = new ArrayList(); + BlockingQueue blockingQueue = new LinkedBlockingQueue(); - // make stops + // make stop" + name + " reached stop " + nextStop.getStopName() + "!"s for (int k = 0; k < numStops; k++) { Stop s = new Stop(k, numPassengersPerStop); s.setBlockingQueue(blockingQueue); @@ -36,14 +38,14 @@ public class App { stops.add(s); s.setThreadPool(threadsStop); threadsStop.submit(s); - //s.run(); } - // make busses for (int k = 0; k < numBusses; k++) { - if (numStopPerBus > numStops) - {System.out.println("More stops per bus than stops."); return;} + if (numStopPerBus > numStops) { + System.out.println("More stops per bus than stops."); + return; + } ArrayList s_list = new ArrayList(); Stop s; @@ -67,7 +69,7 @@ public class App { for (Stop start : b.getStops()) { // make sure passenger can leave. - if (start == b.getTerminus()) + if (start == b.getTerminus()) continue; int idx = b.getStops().indexOf(start); @@ -80,9 +82,12 @@ public class App { dest = b.getStops().get(idx + 1 + (int) Math.round(Math.random() * (numStopPerBus - 2 - idx))); Passenger p = new Passenger(idPassenger, start, dest); + p.setThreadPool(threadsPassenger); passengers.add(p); start.addPassenger(p); idPassenger++; + + threadsPassenger.submit(p); } } } @@ -106,11 +111,15 @@ public class App { threadsBus.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); } catch (InterruptedException e) {} - // block stop pool once bus have finished - + // block stop and passenger pool once bus have finished threadsStop.shutdown(); + threadsPassenger.shutdown(); try { threadsStop.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); } catch (InterruptedException e) {} + + try { + threadsPassenger.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); + } catch (InterruptedException e) {} } } diff --git a/src/main/java/usherbrooke/ift630/Bus.java b/src/main/java/usherbrooke/ift630/Bus.java index 402c4e4..bc0c4d5 100644 --- a/src/main/java/usherbrooke/ift630/Bus.java +++ b/src/main/java/usherbrooke/ift630/Bus.java @@ -2,19 +2,20 @@ package usherbrooke.ift630; import java.util.ArrayList; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutionException; public class Bus extends Thread { - private ArrayList passengers; - private ArrayList stops; - private String name; - private int id; - private int maxCapacity; - private int currentCapacity; - private int timeBetweenStops; - private int timeToNextStop; - private int timeEmbark; - private Stop nextStop; - private BlockingQueue blockingQueue; + private ArrayList passengers; + private ArrayList stops; + private String name; + private int id; + private int maxCapacity; + private int currentCapacity; + private int timeBetweenStops; + private int timeToNextStop; + private int timeEmbark; + private Stop nextStop; + private BlockingQueue blockingQueue; // returns time for a single passenger to embark. private int timeEmbark() { @@ -23,14 +24,14 @@ public class Bus extends Thread { // set time between stop. private int calculateTimeBetweenStops() { - timeToNextStop = (int) ((timeBetweenStops / 3) + (Math.random() * 2 * timeBetweenStops / 3)); + timeToNextStop = (int) ((timeBetweenStops / 3) + (Math.random() * 2 * timeBetweenStops / 3)); return timeToNextStop; } // check if a passenger must leave at next stop. private boolean stopAsked() { boolean res = false; - for (Passenger p : passengers){ + for (Passenger p : passengers) { if (p.getDest() == nextStop) { res = true; Logger.getInstance().print(id, "[BUS] " + name + " stop asked!"); @@ -65,9 +66,9 @@ public class Bus extends Thread { } // send Bus info msg to next stop - private void sendNextStopInfo() throws InterruptedException{ + private void sendNextStopInfo() throws InterruptedException { BusInformationMessage info = new BusInformationMessage(this, nextStop, timeToNextStop); - synchronized(blockingQueue) { + synchronized (blockingQueue) { blockingQueue.put(info); } } @@ -120,22 +121,22 @@ public class Bus extends Thread { nextStop = null; } } - } catch (InterruptedException e) { + } catch (Exception e) { Logger.getInstance().print(id, "[BUS] exception: " + e.toString()); } Logger.getInstance().print(id, "[BUS] " + name + " exiting!"); } Bus(ArrayList s, int id, int timeStop, int timeEmbark, int maxCapacity) { - this.timeBetweenStops = timeStop * 1000 + 1; - this.timeEmbark = timeEmbark * 1000 + 1; - this.name = "Bus n°" + id; - this.id = id; - this.passengers = new ArrayList(); - this.stops = s; - this.nextStop = stops.get(0); - this.currentCapacity = 0; - this.maxCapacity = maxCapacity; + this.timeBetweenStops = timeStop * 1000 + 1; + this.timeEmbark = timeEmbark * 1000 + 1; + this.name = "Bus n°" + id; + this.id = id; + this.passengers = new ArrayList(); + this.stops = s; + this.nextStop = stops.get(0); + this.currentCapacity = 0; + this.maxCapacity = maxCapacity; } // disembark passenger at a stop. Synchronizes, locks on that stop, and waits. @@ -145,11 +146,11 @@ public class Bus extends Thread { for (Passenger p : passengers) { waitEmbark(); - Logger.getInstance().print(id, - "\t[DISEMBARK] " + p.getName() + " at " + nextStop.getStopName()); - if (p.getDest() == nextStop) { - p.disembark(); + synchronized (p) { + p.notify(); + } + // already synced on this, func is synced currentCapacity--; } } @@ -163,15 +164,15 @@ public class Bus extends Thread { try { ArrayList list = nextStop.getPassengerByDest(stops); for (Passenger p : list) { + synchronized (p) { + p.notify(); + } waitEmbark(); if (currentCapacity >= maxCapacity) continue; passengers.add(p); nextStop.removePassenger(p); currentCapacity++; - - Logger.getInstance().print(id, - "\t[EMBARK] " + p.getName() + " at " + nextStop.getStopName()); } } catch (IndexOutOfBoundsException e) { Logger.getInstance().print(id, "Exception: " + e.getMessage()); @@ -188,7 +189,6 @@ public class Bus extends Thread { Logger.getInstance().print(id, "\t".repeat(indent) + "current stop: " + nextStop.getStopName()); Logger.getInstance().print(id, "\t".repeat(indent) + "stops: "); - if (nextStop != stops.get(0)) nextStop.printDetails(id, indent + 1); for (Stop s : stops) { diff --git a/src/main/java/usherbrooke/ift630/Passenger.java b/src/main/java/usherbrooke/ift630/Passenger.java index df1213c..ec52748 100644 --- a/src/main/java/usherbrooke/ift630/Passenger.java +++ b/src/main/java/usherbrooke/ift630/Passenger.java @@ -1,24 +1,57 @@ package usherbrooke.ift630; -public class Passenger { +import java.util.concurrent.Future; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; - private String name; - private int id; - private Stop dest; - private Stop start; +public class Passenger extends Thread { - Passenger(int id, Stop start, Stop dest) { + private String name; + private int id; + private Stop dest; + private Stop start; + private ExecutorService threads; + private ExecutorService ex; + private Future future; + + Passenger(int id, Stop start, Stop dest) { this.id = id; this.name = "Passenger " + id; this.dest = dest; this.start = start; - } + this.ex = Executors.newFixedThreadPool(2); // one for each future. + } - // unused, *yet* - public synchronized void embark() {} + public void run() { + try { + embark(); + disembark(); + } catch (Exception e) { + Logger.getInstance().print(id, "[PASSENGER] " + e.toString()); + } + } - // unused, *yet* - public synchronized void disembark() {} + // embark people once thread notified + private synchronized Future embark() { + return ex.submit(() -> { + synchronized (this) { + wait(); + } + Logger.getInstance().print(id, "\t[PASSENGER] I'm embarking at " + start.getStopName()); + return null; + }); + } + + // disembark people once thread notified another time. + private synchronized Future disembark() { + return ex.submit(() -> { + synchronized (this) { + wait(); + } + Logger.getInstance().print(id, "\t[PASSENGER] I'm leaving at " + dest.getStopName()); + return null; + }); + } public Stop getStart() { return start; @@ -28,24 +61,31 @@ public class Passenger { return dest; } - public String getName() { + public String getPassengerName() { return name; } // Pretty print, with color! public void printDetails(int color, int indent) { - Logger.getInstance().print(color, "\t".repeat(indent) + "---".repeat(3) + " Passenger details " + "---".repeat(3)); - Logger.getInstance().print(color, "\t".repeat(indent) + name + " start: " + start.getStopName() + " dest: " + dest.getStopName()); + Logger.getInstance().print(color, + "\t".repeat(indent) + "---".repeat(3) + " Passenger details " + "---".repeat(3)); + Logger.getInstance().print(color, + "\t".repeat(indent) + name + " start: " + start.getStopName() + " dest: " + dest.getStopName()); } // Pretty print, with indent! public void printDetails(int indent) { Logger.getInstance().print(id, "\t".repeat(indent) + "---".repeat(3) + " Passenger details " + "---".repeat(3)); - Logger.getInstance().print(id, "\t".repeat(indent) + name + " start: " + start.getStopName() + " dest: " + dest.getStopName()); + Logger.getInstance().print(id, + "\t".repeat(indent) + name + " start: " + start.getStopName() + " dest: " + dest.getStopName()); } // Pretty print! public void printDetails() { printDetails(0); } + + public void setThreadPool(ExecutorService threads) { + this.threads = threads; + } } diff --git a/src/main/java/usherbrooke/ift630/Stop.java b/src/main/java/usherbrooke/ift630/Stop.java index b370dc7..9e817d6 100644 --- a/src/main/java/usherbrooke/ift630/Stop.java +++ b/src/main/java/usherbrooke/ift630/Stop.java @@ -1,21 +1,21 @@ package usherbrooke.ift630; -import java.util.ArrayList; +import java.util.concurrent.Executors; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; +import java.util.ArrayList; public class Stop extends Thread { - private String name; - private int id; - private int maxCapacity; - private int indent = 0; - private ArrayList passengers; - private ExecutorService threads; - private BlockingQueue blockingQueue; - + private String name; + private int id; + private int maxCapacity; + private int indent = 0; + private ArrayList passengers; + private ExecutorService threads; + private BlockingQueue blockingQueue; // print bus info times. - private void displayInfos(int indent) throws InterruptedException, ExitException{ + private void displayInfos(int indent) throws InterruptedException, ExitException { BusInformationMessage info = null; // lock queue, get head @@ -30,7 +30,8 @@ public class Stop extends Thread { Logger.getInstance().print(id, "\t".repeat(indent) + "[STOP] " + info.getBus(this).getNameBus() + " arrives in " + time + "s"); // else, catch - } catch (NullPointerException e) {} + } catch (NullPointerException e) { + } } catch (UnauthorizedException e) { // if unauth, requeue message. @@ -41,8 +42,13 @@ public class Stop extends Thread { // loop, and ensure that every stop is reactive synchronized (this) { - threads.submit(this); + // i dont have access to virtual threads, and futures are for the next question. + // to not hog allof the pool's capacity, + // i have to manualy change threads in action. This is done by submiting this + // thread, waiting a bit (dont blow up our CPU) then exit. This ensure that + // another thread takes the slot, if it there is one. sleep(10); + threads.submit(this); throw new ExitException(); } } @@ -53,7 +59,8 @@ public class Stop extends Thread { for (;;) { displayInfos(indent); } - } catch (InterruptedException | ExitException e) {} + } catch (InterruptedException | ExitException e) { + } } Stop(int id, int maxCapacity) { @@ -118,7 +125,7 @@ public class Stop extends Thread { printDetails(0); } - public void removePassenger(Passenger p) { + public synchronized void removePassenger(Passenger p) { try { passengers.remove(p); } catch (Exception e) {