2016-08-02 3 views
1

В настоящее время я пишу программу, имитирующую сеть метро. Я достиг стадии в программе, где симуляция работает, и может имитировать станции, поезда, маршруты, маршруты и платформы. Однако, несмотря на работу в течение определенного периода времени, в какой-то момент у меня возникает проблема с ArrayList.Параллельные потоки и последующая проблема с 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. 
    } 
} 

Самое странное в том, что этот метод работает в течение периода времени, прежде, чем ява начинает бросать IndexOutOfBounds исключения. Этот метод является частью моего класса Train и вызывается только его собственным методом запуска и никогда не имеет другого класса. У меня есть метод 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

Пожалуйста, полностью разместите свой код, чтобы ответить – Shriram

+0

Является ли «маршрут» изменен структурно в другом месте класса? Эти места также синхронизированы? –

+0

@ Шрирам, я загрузил свой полный класс поезда. – SensibleCape11

ответ

0

Поэтому я подробно рассмотрел updateItinerary. Проблема возникла из маршрута route = (ArrayList) route.getEdgeList() ;, поскольку это была ссылка на мою структуру данных, а не на копию. Поэтому он случайно удалял дорожки!

Смежные вопросы