This is Java Implementation of the Semaphore based solution for Senate Bus Problem
https://github.com/Rajind/SenateBusProblem
The Senate Bus Problem (From The Little Book of Semaphores by Allen B. Downey)
This problem was originally based on the Senate bus at Wellesley College. Riders come to a bus stop and wait for a bus. When the bus arrives, all the waiting riders invoke boardBus, but anyone who arrives while the bus is boarding has to wait for the next bus. The capacity of the bus is 50 people; if there are more than 50 people waiting, some will have to wait for the next bus. When all the waiting riders have boarded, the bus can invoke depart. If the bus arrives when there are no riders, it should depart immediately.
import java.util.Scanner;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
*
* @author Rajind
*/
public class Simulation {
private static final SharedData sharedData = new SharedData();
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
System.out.print("Enter the number of Riders : ");
int rider_count = scanner.nextInt();
System.out.println("");
new Bus(sharedData).busActivity();
for(int i=0; i < rider_count ; i++){
new Rider(sharedData).start();
}
}
}
class SharedData {
private final AtomicInteger waiting_riders_count = new AtomicInteger(0);
private final Semaphore riders_mutex = new Semaphore(1);
private final Semaphore bus = new Semaphore(0);
private final Semaphore boarded = new Semaphore(0);
public AtomicInteger getWaiting_riders_count() {
return waiting_riders_count;
}
public Semaphore getRiders_mutex() {
return riders_mutex;
}
public Semaphore getBus() {
return bus;
}
public Semaphore getBoarded() {
return boarded;
}
}
class Rider extends Thread{
private final SharedData sharedData;
public Rider(SharedData sharedData) {
this.sharedData = sharedData;
}
@Override
public void run(){
this.runMethod();
}
private void runMethod(){
try {
/*
New rider that comes to the bus stop waits on the riders mutex
to enter the queue (to update waiting_riders_count value)
*/
sharedData.getRiders_mutex().acquire();
/*
New rider acuires the riders mutex
*/
System.out.println("Riders mutex aquired by a Rider");
} catch (InterruptedException ex) {
Logger.getLogger(Rider.class.getName()).log(Level.SEVERE, null, ex);
}
sharedData.getWaiting_riders_count().incrementAndGet();
/*
New rider enters the queue by incrementing waiting_riders_count value
*/
sharedData.getRiders_mutex().release();
/*
New rider releases the riders mutex after entering the queue
*/
System.out.println("Riders mutex released by Rider");
try {
/*
Now the rider wait to aqcuire the bus semaphore to enter the bus.
It has to wait till Bus signals to acquire the lock.
*/
sharedData.getBus().acquire();
/*
Rider is able to acquire the bus semaphore
*/
System.out.println("Bus semaphore acquired by a Rider");
} catch (InterruptedException ex) {
Logger.getLogger(Rider.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("Rider boards bus");
sharedData.getBoarded().release();
/*
Rider signals that he has boarded
*/
System.out.println("Boarded semaphore released by Rider");
}
}
class Bus implements Runnable{
//number of passengers bus can take in one turn
private final int SEAT_LIMIT = 50;
//initial time before bus comes to the station
private final int TERMINATION_TIME = 60; //60 seconds
//time delay after completion of one bus turn
private final int DELAY_AFTER_ONE_TURN = 2; //2 seconds
//initial time delay for the Bus
private final int INITIAL_DELAY = 1; //1 seconds
private final SharedData sharedData;
private final ScheduledExecutorService scheduler;
public Bus(SharedData sharedData) {
this.scheduler = Executors.newScheduledThreadPool(1);
this.sharedData = sharedData;
}
public void busActivity(){
final Runnable senateBus = new Runnable() {
public void run() {
runMethod();
}
};
/*executes a periodic action that becomes enabled first after the given
initial delay, and subsequently with the given delay between the termination
of one execution and the commencement of the next.
*/
final ScheduledFuture<?> busHandle =
scheduler.scheduleWithFixedDelay(senateBus, INITIAL_DELAY, DELAY_AFTER_ONE_TURN, TimeUnit.SECONDS);
//executes a schedule future after a given delay
scheduler.schedule(new Runnable(){
public void run() {
busHandle.cancel(true);
System.exit(0);
}
}, TERMINATION_TIME, TimeUnit.SECONDS);
}
@Override
public void run() {
this.runMethod();
}
private void runMethod(){
try {
/*
Bus waits to acquire riders mutex so that it can start boarding
*/
sharedData.getRiders_mutex().acquire();
/*
Bus acquired writers lock. So now no other Rider can enter the queue
till the Bus releases the lock
*/
System.out.println("Riders mutex aquired by Bus");
//System.out.println("Bus came to the stop & locked riders_count");
} catch (InterruptedException ex) {
Logger.getLogger(Bus.class.getName()).log(Level.SEVERE, null, ex);
}
int boarding_riders_count = Math.min(sharedData.getWaiting_riders_count().get(), SEAT_LIMIT);
/*if there are riders more than the value of SEAT_LIMIT waiing then
we set r_count to SEAT_LIMIT
*/
System.out.format("\nWaiting riders count: %d\n",sharedData.getWaiting_riders_count().get());
System.out.format("\nBoarding riders count: %d\n", boarding_riders_count);
for(int i=0; i < boarding_riders_count; i++){
/*
Bus signals riders that one of them can enter
*/
sharedData.getBus().release();
System.out.println("Bus semaphore released by Bus");
try {
sharedData.getBoarded().acquire();
/*
Bus aquires boarded sepahore to say rider has boarded
*/
System.out.println("Boarded semaphore aquired by Bus");
} catch (InterruptedException ex) {
Logger.getLogger(Bus.class.getName()).log(Level.SEVERE, null, ex);
}
}
int n = sharedData.getWaiting_riders_count().get();
sharedData.getWaiting_riders_count().set(Math.max(n - 50, 0));
/*
if(sharedData.getWaiting_riders_count().get() == 0){
System.exit(0);
}*/
sharedData.getRiders_mutex().release();
/*
Bus updates waiting queue count and releases lock
*/
System.out.println("Riders mutex released by Bus");
System.out.println("Bus Departs");
}
}
Class “Simulation” contains the main method.
If you are using the command prompt :
1) compile it using : javac Simulation.java
2) run it using : java Simulation
You will be prompted to enter a integer parameter to rider count.
Using paramater in Class Bus,
Program is set to terminate after 60 seconds.(TERMINATION_TIME)
Delay after one bus turn is set to 2 seconds. (DELAY_AFTER_ONE_TURN)
Intial delay for bus arrival is set to 1 seconds. (INITIAL_DELAY)
~Rajind Ruparathna