got a task with a different variation of the classic problem. We have a bridge between North and South, n number of objects trying to cross from North, and s number of objects trying to cross from south.(each object runs on its own thread). In this case the object is a Farmer. All the threads start at the same time so the output should vary depending on who gets to the semaphore first.
I understand many variations of this have been asked but I cannot seem to find one too closely related to my problem that I can understand.
I have implemented a perfectly functioning "one at a time" crossing using a single java.util.concurrent.Semaphore on my bridge but am struggling to upgrade it to meet the new criteria for the next question.
The problem is that they must now cross in pairs, and both pairs must be from the same side of the bridge, so 2 can cross from North together or 2 from South together, and not at all if there is only 1 left on that side (needs to loop endlessly trying to cross).
I don't expect you to answer my assignment question for me but any help pointing me in the right direction using java semaphores would be great. My understanding is I have to have my semaphore have a max of 2 (easy enough) and I have to lock the bridge until 2 objects from a certain side are ready to cross (not as easy).
Example output for one at a time crossing on N=3 S=4
Question 2.
N_Farmer1: Waiting for bridge. Going towards South
N_Farmer2: Waiting for bridge. Going towards South
N_Farmer3: Waiting for bridge. Going towards South
S_Farmer1: Waiting for bridge. Going towards North
S_Farmer2: Waiting for bridge. Going towards North
S_Farmer3: Waiting for bridge. Going towards North
S_Farmer4: Waiting for bridge. Going towards North
N_Farmer1: Crossing bridge Step 5.
N_Farmer1: Crossing bridge Step 10.
N_Farmer1: Crossing bridge Step 15.
N_Farmer1: Across the Bridge.
NEON = 1
N_Farmer2: Crossing bridge Step 5.
N_Farmer2: Crossing bridge Step 10.
N_Farmer2: Crossing bridge Step 15.
N_Farmer2: Across the Bridge.
NEON = 2
N_Farmer3: Crossing bridge Step 5.
N_Farmer3: Crossing bridge Step 10.
N_Farmer3: Crossing bridge Step 15.
N_Farmer3: Across the Bridge.
NEON = 3
S_Farmer2: Crossing bridge Step 5.
S_Farmer2: Crossing bridge Step 10.
S_Farmer2: Crossing bridge Step 15.
S_Farmer2: Across the Bridge.
NEON = 4
S_Farmer1: Crossing bridge Step 5.
S_Farmer1: Crossing bridge Step 10.
S_Farmer1: Crossing bridge Step 15.
S_Farmer1: Across the Bridge.
NEON = 5
S_Farmer3: Crossing bridge Step 5.
S_Farmer3: Crossing bridge Step 10.
S_Farmer3: Crossing bridge Step 15.
S_Farmer3: Across the Bridge.
NEON = 6
S_Farmer4: Crossing bridge Step 5.
S_Farmer4: Crossing bridge Step 10.
S_Farmer4: Crossing bridge Step 15.
S_Farmer4: Across the Bridge.
NEON = 7
my code Bridge.java
public class Bridge {
private int crossed; //Count the number of crossings
private Semaphore bridgeSem; //semaphore to only allow 1 crossing at a time
//Constructor
public Bridge() {
crossed=0;
bridgeSem = new Semaphore(1); //one bridge resource, mutual exclusivity
}
//Getters
public int getCrossed() {
return crossed;
}
//Methods
public void cross() {
//Semaphore acquire
try {
bridgeSem.acquire();
crossed++; //increment NEON counter
}
catch (InterruptedException e) {}
}
public void exit() {
//Semaphore release
bridgeSem.release();
}
}
Farmer.java:
public class Farmer extends Thread{
private String location; //current location
private String destination; //Opposite location, destination, set in the constructor
private String id; //name
private Bridge bridge; //bridge being used
//constructor
public Farmer(String id, String location, Bridge bridge) {
this.id=id;
this.location=location;
if (location=="North") destination="South"; //Island objects are not necessary for this particular implementation, as our options are merely North or South
else destination="North";
this.bridge = bridge;
System.out.println(id+": Waiting for bridge. Going towards "+destination); //print initial waiting for bridge
}
//getters
public String getLocation() {
return location;
}
public String getID() {
return id;
}
//Do not need setters, none of the instance variables need to change
@Override //initiatied when the thread.start() method is called
public void run() {
//***initiate critical section requiring semaphore***
bridge.cross();
System.out.println(id+": Crossing bridge Step 5.");
System.out.println(id+": Crossing bridge Step 10.");
System.out.println(id+": Crossing bridge Step 15.");
//Sleep for 200 units ,improves readability (else output is too fast)
try {
Thread.sleep(200);
} catch (InterruptedException e) {} //No interrupts implemented, so thread shouldn't be interrupted?
System.out.println(id+": Across the Bridge.");
System.out.println("NEON = "+bridge.getCrossed());
bridge.exit();
//***end critical section***
//Sleep for 20 units, prevents hogging of semaphore(starvation)
try {
Thread.sleep(20);
} catch (InterruptedException e) {}
}//end run
}//end class
Main:
public static void main(String[] args) {
System.out.println("Question 2.");
int N=3,S=4; //DEBUG, add file reading later
Bridge bridge = new Bridge(); //create our bridge
Farmer[] f = new Farmer[N+S]; //array of Farmers
//create North farmers
for (int i=0; i<N; i++) {
f[i] = new Farmer("N_Farmer"+(i+1),"North",bridge);
}
//create South farmers
for (int i=N; i<S+N; i++) {
f[i]= new Farmer("S_Farmer"+(i-N+1),"South",bridge);
}
//start all farmers
for (int i=0;i<S+N;i++) {
f[i].start(); //start Farmer Threads. Farmers can run start, as Farmer extends thread
}
}