我目前正在编写一个模拟城域网的程序。我已经到了模拟工作的程序阶段,可以模拟车站,火车,轨道,路线和平台。但是,尽管工作了一段时间,但在某些时候,我遇到了一个与ArrayList有关的问题。
每列火车都有一个行程,这是一个轨道的ArrayList,它必须遍历它的旅程。每次火车到达车站时,第一个元素被移除。当火车到达旅程结束时,它会找到相反的路线。
以下是我更新路线的方法。
private synchronized void updateItinerary() {
itinerary.remove(0); // Remove the first element.
if (itinerary.isEmpty()) {
String id = this.id.substring(0,3) + "-" + Track.generateTrackId(route.getEndVertex().id, route.getStartVertex().id); // Get the route identification.
route = metro.routes.get(id); // Retrieve the new route, and switch.
itinerary = (ArrayList<Track>) route.getEdgeList(); // Update the itinerary.
}
}
奇怪的是,在java开始抛出IndexOutOfBounds
异常之前,这种方法可以运行一段时间。该方法是我的Train
类的一部分,并且只由它自己的run方法调用,而不是任何其他类。我有synchronized
方法,但这没有帮助。
有什么想法吗?
完整Train
班级:
package metro;
import java.util.ArrayList;
import org.jgrapht.graph.GraphPathImpl;
/**
* Represents a train on the network.
* @author J.D. Preece
*/
public class Train implements Runnable {
protected static int trainId = 0; // A unique serial number for each train created.
protected ArrayList<Track> itinerary; // The tracks that this train is to cover on this journey.
protected boolean inTransit; // Indicates whether the train is in transit or not.
protected GraphPathImpl<Station, Track> route; // The route this train is on.
protected int delay; // The delay of this train.
protected Metro metro; // The metro network this train is on.
protected Platform platform; // The platform this train is currently on.
protected Station station; // The station this train is currently at.
protected String id; // The identification token of this train.
protected Track track; // The track this train is currently on.
/**
* Creates a new train.
* @param id The identification token of this train.
* @param metro The metro network this train is on.
* @param track The track this train is starting on.
* @param route The route this train is starting on.
*/
public Train(String id, Metro metro, Track track, GraphPathImpl<Station, Track> route) {
this.inTransit = true; // Declares the train is in transit.
this.delay = 0; // Sets the initial delay to 0.
this.metro = metro;
this.track = track;
this.route = route;
this.station = null;
this.id = id;
this.itinerary = generateInitialItinerary(); // Generate the initial itinerary for this train.
}
/**
* Generates an identification token for a train.
* @param routeId The identification token of the route the train is on.
* @return An identification token for a train. The token will be the three letters of the line it is on, followed by a unique number.
*/
public static String generateTrainId(String routeId) {
trainId++;
return routeId.substring(0,3) + String.format("%03d", trainId);
}
/**
* Simulates a train running.
*/
@Override
public void run() {
try {
while (true) {
if (inTransit) {
traverseTrack(); // Travel across the current section of track, until it reaches the end.
joinStationQueue(track.target); // Join the queue for the next station to wait for an available platform.
arriveAtStation(track.target); // Update the current station of this train, and free the track it has just left.
} else {
joinTrackQueue(itinerary.get(0)); // Wait until the next set of track is free.
departStation(); // Depart the station, and join the next track.
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* Determines what the train does as it traverses across the track it is on.
* @throws InterruptedException
*/
private void traverseTrack() throws InterruptedException {
double locationOnTrack = 0; // Indicates where the train is on this section of track.
while (locationOnTrack < track.weight) {
Thread.sleep(1); // Sleep briefly.
locationOnTrack++; // Iterate the location of this train on this section of track.
}
}
/**
* Adds this train to the queue for a platform at the next station, and waits to be notified of a free platform.
* @param station
* @throws InterruptedException
*/
private void joinStationQueue(Station station) throws InterruptedException {
synchronized (station) {
station.waitingTrains.add(this); // Add this train to the target station queue.
}
System.out.println("The next station for " + id + " is " + station.toString()); // Outputs the arrival to the console.
synchronized (this) {
this.wait(); // Wait until a notification is received.
}
}
/**
* Adds this train to the queue to use this section of track, and waits to be notified that it is free.
* @throws InterruptedException
*/
private void joinTrackQueue(Track track) throws InterruptedException {
synchronized (track) {
track.waitingTrains.add(this);
}
synchronized (this) {
this.wait();
}
}
/**
* Updates the current station of this train, and frees the track it was just on.
* @param station The station this train is arriving at.
*/
private void arriveAtStation(Station station) {
inTransit = false; // Declares that the train is no longer in transit.
this.station = station; // Updates the current station.
synchronized (track) {
track.notify(); // Notify the track that it is now free.
track = null; // Removes the reference to that section of track.
}
updateItinerary();
System.out.println(id + " has arrived at " + station);
System.out.println(id + " " + itinerary);
}
/**
* Departs the train from the current station, and notifies the station of the departure.
*/
private void departStation() {
synchronized (platform) {
platform.notify(); // Notifies the platform of the departure.
platform = null; // Removes the current platform reference.
station = null; // Removes the current station reference.
inTransit = true; // Declares that the train is now in transit.
}
}
/**
* Generates the initial itinerary for the train.
* @return A list of tracks to be traversed until the destination station.
*/
private ArrayList<Track> generateInitialItinerary() {
ArrayList<Track> newList = new ArrayList<Track>(route.getEdgeList());
for (Track track : route.getEdgeList()) {
if (this.track.equals(track)) {
return newList; // If the current track being checked is the track the train is actually on, return the itinerary.
} else {
newList.remove(0); // Remove redundant track.
}
}
return newList;
}
/**
* Updates the itinerary of this train. If the train has reached the end of its previous journey, it is given a new one in the opposite direction.
*/
private synchronized void updateItinerary() {
itinerary.remove(0);
if (itinerary.isEmpty()) {
String id = this.id.substring(0,3) + "-" + Track.generateTrackId(route.getEndVertex().id, route.getStartVertex().id);
route = metro.routes.get(id); // Switch routes.
itinerary = (ArrayList<Track>) route.getEdgeList(); // Update the itinerary.
}
}
/**
* Outputs this train as a string.
* @return Information on this train.
*/
public String toString() {
return "[" + id + "]";
}
堆栈跟踪对于整个事物来说太长了,所以我以火车KEN078
为例。
The next station for KEN078 is [12 : Station Hill]
KEN078 has arrived at [12 : Station Hill]
KEN078 [[42:47 : Kennet Island : Madjeski Stadium : 900.0], [47:51 : Madjeski Stadium : Reading International Business Park : 950.0], [51:53 : Reading International Business Park : Three Mile Cross : 850.0]]
---
The next station for KEN078 is [47 : Madjeski Stadium]
Exception in thread "Thread-546" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:653)
at java.util.ArrayList.get(ArrayList.java:429)
at metro.Train.run(Train.java:65)
at java.lang.Thread.run(Thread.java:745)
The next station for SUT117 is [38 : Theale]
KEN078 has arrived at [47 : Madjeski Stadium]
KEN078 []
答案 0 :(得分:0)
所以我仔细看了一下updateItinerary。问题来自行itinerary =(ArrayList)route.getEdgeList();,因为它是对我的数据结构的引用,而不是副本。因此,它无意中删除了曲目!