I'm having a hard time understanding multithreading. Unfortunately, this is one of the assignments I need to submit in order to pass the course.
It's about a train: -The train waits for the Passenger Thread to send some passengers until the capacity is reached.
Then the train goes for a ride. During this period, no passengers can board the train.
The next step is unboarding, this is a procedure called by the Passenger thread.
Once this happens, the cycle goes on with the rest of passengers.
I'm having trouble in the unboarding part, sometimes I get an exception for array out of bounds.
Here's the error:
Passenger 3 has boarded the train
Passenger 0 has boarded the train
Passenger 1 has boarded the train
Passenger 12 has boarded the train
Passenger 13 has boarded the train
TRAIN FULL
SEAT: 0 Passenger: 3
SEAT: 1 Passenger: 0
SEAT: 2 Passenger: 1
SEAT: 3 Passenger: 12
SEAT: 4 Passenger: 13
RIDE STARTS
RIDE ENDS
Passenger 3 wants to get off the train. SEAT: 0
Passenger: 3 off the train
Passenger(s) left: 0
Passenger(s) left: 1
Exception in thread "Thread-16" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(Unknown Source)
at java.util.ArrayList.remove(Unknown Source)
at parque.Train.unboardTrain(Train.java:104)
at parque.Passenger.run(Passenger.java:23)
Passenger(s) left: 12
Passenger(s) left: 13
Passenger 15 wants to get off the train. SEAT: -1 //There is no passengerID 15, huh?
I would like to know how can I avoid this exception?, I was thinking maybe implementing another lock separate from the train lock, that would be in charge of the doors, or maybe this should be implemented as a condition?, help please
Here's the code:
public class Train extends Thread {
private int id;
private int capacity;
private ArrayList<Integer> passengers;
private Lock l = new ReentrantLock();
private Condition trainFull = l.newCondition();
private Condition boardTrain = l.newCondition();
private Condition UnboardTrain = l.newCondition();
private boolean canBoard = true;
private boolean canUnboard = false;
//se definen los constructores
public Train(int id, int capacity) {
this.id = id;
this.capacity = capacity;
this.passengers = new ArrayList<Integer>(capacity);
}//fin constructor
public Train(int id) {
this.id = id;
this.capacity = 5;
passengers = new ArrayList<Integer>(capacity);
}//fin constructor
public void boardTrain(int passengerId) {
l.lock();
try{
while(!canBoard)
boardTrain.await();
if (passengers.size() == capacity) {
canBoard = false;
trainFull.signal();
} else {
passengers.add(passengerId);
System.out.println("Passenger " + passengerId +" has boarded the train");
}//if
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("Exception at boarding");
}finally{
l.unlock();
}//try
}//fin subir
public void waitsFullTrain() { //waits until n (capacity) passengers board the train
l.lock();
try{
trainFull.await();
System.out.println("TRAIN FULL");
for(int i = 0; i< passengers.size(); i++){
System.out.println(" SEAT: " + i + " Passenger: " + passengers.get(i));
}//for
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
l.unlock();
}//try
}//fin esperaLleno
public void goForRide() throws InterruptedException{
l.lock();
try{
System.out.println("RIDE STARTS");
Thread.sleep(2000);
System.out.println("RIDE ENDS");
canUnboard = true;
UnboardTrain.signalAll();
}finally{
l.unlock();
}
}//fin darVuelta
public void unboardTrain(int pasajeroId) {
l.lock();
try{
while(!canUnboard)
UnboardTrain.await();
//System.out.println("Bajando..");
if(passengers.size() >0){
System.out.println("Passenger "+ pasajeroId + " wants to get off the train. SEAT: "+passengers.indexOf(pasajeroId) );
passengers.remove(passengers.indexOf(pasajeroId));
System.out.println(" Passenger: " + pasajeroId + " off the train");
for (int i = 0; i<passengers.size();i++){
System.out.println(" Passenger(s) left: "+passengers.get(i));
}
}else{
System.out.println();
canUnboard = false;
canBoard = true;
boardTrain.signalAll();
}//if
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("Exception at unboarding");
}finally{
l.unlock();
}//try
}//fin bajar
public int id() {
return id;
}//fin id
@Override
public void run() {
while(true){
this.waitsFullTrain();
try {
this.goForRide();
} catch (InterruptedException e) {
e.printStackTrace();
}
}//fin while
}//fin run
}//fin clase
public class Passenger extends Thread{
private int id;
private Train t;
public Passenger(int id, Train t) {
this.id = id;
this.t = t;
}
@Override
public void run() {
t.boardTrain(this.id);
t.unboardTrain(this.id);
}//run
}//Passenger
public class Main {
public static void main(String[] args) {
Train t = new Train(1);
Passenger[] p = new Passenger[20];
for (int i = 0; i < p.length; i++) {
p[i]= new Passenger(i, t);
}//for
t.start();
for (int i = 0; i < p.length; i++) {
p[i].start();
}//for
try {
t.join();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
for (int i = 0; i < p.length; i++) {
try {
p[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}//for
}//main
}//clase