2012-03-06 2 views
0

나는 순환 큐와 스레딩을 사용하여 열차를 타고 올라가고 승객을 떨어 뜨리는 프로젝트를 만들고있다. Object.notify와 Object.wait을 사용하여 스레드를 제어하고 있습니다. 나는 응용 프로그램을 스레딩에 새로운 오전과 내가 이해하지 못하는이 오류가 무엇입니까 : 여기Java threading, monitor etc .... 내 머리를 감싸는 것.

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at Station.run(Station.java:37) 
    at java.lang.Thread.run(Unknown Source) 

것은 내 주요 여기

public static void main(String[] args) 
    { 
     Track theTrack = new Track(); 
     Station[] stations = {new Station(TRAIN_STATION_TYPE.ASHMONT)}; 
     Train[] trains = {new Train(TRAIN_TYPE.A_TRAIN, theTrack)}; 

     Thread[] stationThreads = new Thread[stations.length]; 
     Thread[] trainThreads = new Thread[trains.length]; 

     theTrack.setStations(stations); 
     theTrack.setTrains(trains); 
     for(int i = 0; i<stations.length; i++) 
     { 
      stationThreads[i] = new Thread(stations[i]); 
      stationThreads[i].start(); 
     } 
     for(int i = 0; i<trains.length; i++) 
     { 
      trainThreads[i] = new Thread(trains[i]); 
      trainThreads[i].start(); 
     } 
    } 

은 각 트랙을 따라 이동 내 기차 클래스입니다 역 이탈 및 픽업 승객 : 여기
public class Train implements Runnable 
{ 
    TRAIN_TYPE trainType; 
    int location; 
    private boolean goingForward, trainIsRunning; 
    private Track track; 
    private CircularQueue <Passenger> passengers; 
    private Station stationBoarded; 
    Train() 
    { 
     this(null); 
    } 
    Train(TRAIN_TYPE trainType) 
    { 
     this(trainType, null); 
    } 
    Train(TRAIN_TYPE trainType, Track track) 
    { 
     this.trainType = trainType; 
     location = trainType.location(); 
     this.track = track; 
     trainIsRunning = true; 
     goingForward = true; 
    } 
    @Override 
    public void run() 
    { 
     while(trainIsRunning) 
     { 
      moveTrain();// train is moving up or down the track until it hits the location of a station 
      setStationBoarded(track.arriveAtStation(location)); // board station 
      stationBoarded.queueTrain(this);// queue this train 
      justWait(); // wait to be notified 
      unloadPassengers();// unload passengers 
      stationBoarded.notify();//notify station boarded to allow passengers to board the train. 
      justWait(); // wait to be notified to leave 
      depart(); 
     } 
    } 
    public boolean boardTrain(Passenger p) 
    { 
     if(!passengers.reachedCapacity()) 
     { 
      passengers.enqueue(p); 
      return true; 
     } 
      return false; 
    } 
    public void moveTrain() 
    { 
     while(track.arriveAtStation(location) == null) 
     { 
      TIME_CONSTANT.TRAIN_MOVE_TIME.sleepAWhile(); 
      if(goingForward) 
       location++; 
      else 
       location--; 
      if(!track.isOnTrack(location)) 
       goingForward = !goingForward; 
     } 
    } 
    public void unloadPassengers() 
    { 
     for(int i = 0; i<passengers.getLength(); i++) 
     { 
      if(passengers.peekAtIndex(i).getDestination() == stationBoarded.getTrainStation()) 
       stationBoarded.queuePassenger(passengers.remove(passengers.peekAtIndex(i))); 
     } 
    } 
    public synchronized void justWait() 
    { 
     try { 
      wait(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
    public void depart() 
    { 
     this.stationBoarded = null; 
    } 
    public synchronized Passenger leaveTrain() 
    { 
     return passengers.dequeue(); 
    } 
    public boolean isTrainIsRunning() { 
     return trainIsRunning; 
    } 
    public void setTrainIsRunning(boolean trainIsRunning) { 
     this.trainIsRunning = trainIsRunning; 
    } 
    public int getLocation() { 
     return location; 
    } 
    public void setLocation(int location) { 
     this.location = location; 
    } 
    public int getCapacity() 
    { 
     return this.trainType.capacity(); 
    } 
    public Station getStationBoarded() 
    { 
     return stationBoarded; 
    } 
    public void setStationBoarded(Station stationBoarded) { 
     this.stationBoarded = stationBoarded; 
    } 
    public boolean trainIsEmpty() 
    { 
     return this.passengers.isEmpty(); 
    } 
    public boolean trainHasReachedCapacity() 
    { 
     return passengers.reachedCapacity(); 
    } 
    public Track getTrack() { 
     return track; 
    } 
    public void setTrack(Track track) { 
     this.track = track; 
    } 
} 

은 그것이 기차를 기다리는 동안 역 탑승 기차에가는 승객을 생성하는 내 역 클래스 :

import java.util.Random;

public class Station implements Runnable 
{ 
    CircularQueue <Passenger> passengers; 
    CircularQueue <Train> trains; 
    TRAIN_STATION_TYPE trainStation; 
    Train trainInStation; 
    int location, numOfPassengers; 
    Passenger tempPassenger; 
    Random ran = new Random(); 
    Station() 
    { 
     this (null); 
    } 
    Station(TRAIN_STATION_TYPE tranStation) 
    { 
     this(tranStation, null); 
    } 
    Station(TRAIN_STATION_TYPE trainStation, Train train) 
    { 
     this.trainStation = trainStation; 
     this.trainInStation = train; 
     this.trains = new CircularQueue(); 
     this.passengers = new CircularQueue(); 
    } 
    public void run() 
    { 
     while(trains.isEmpty()) 
     { 
      genPassengers(); 
     } 
     while(!trains.isEmpty()) 
     { 
      trainInStation = trains.dequeue(); 
      trainInStation.notify(); // notify the train to let the passengers off 
      justWait(); // wait for train to unload passengers 
      unloadPassengers(); 
      trainInStation.notify();//notify the train to depart 
      departTrain(); 
     } 
    } 
    public void genPassengers() 
    { 
     TIME_CONSTANT.PASSENGER_GEN_TIME.sleepAWhile(); 
     passengers.enqueue(new Passenger()); 
    } 
    public void departTrain() 
    { 
     trainInStation = null; 
    } 
    public void arrive(Train train) 
    { 
     this.trainInStation = train; 
    } 
    public Train depart() 
    { 
     Train tempTrain = this.trainInStation; 
     this.trainInStation = null; 
     return tempTrain; 
    } 
    public int getLocation() { 
     return location; 
    } 
    public void setLocation(int location) { 
     this.location = location; 
    } 
    public boolean isBoarded() 
    { 
     return (trainInStation != null); 
    } 
    public Train getTrain() { 
     return trainInStation; 
    } 
    public void setTrain(Train train) { 
     this.trainInStation = train; 
    } 
    public synchronized void queueTrain(Train train) { 
     trains.enqueue(train); 
    } 
    public synchronized Train dequeue() { 
     return trains.dequeue(); 
    } 
    public synchronized void queuePassenger(Passenger passenger){ 
     passengers.enqueue(passenger); 
    } 
    public synchronized Passenger dequeuePassenger() 
    { 
     return passengers.dequeue(); 
    } 
    public TRAIN_STATION_TYPE getTrainStation() { 
     return trainStation; 
    } 
    public void setTrainStation(TRAIN_STATION_TYPE trainStation) { 
     this.trainStation = trainStation; 
    } 
    public void justWait() 
    { 
     try { 
      this.wait(); //wait for passengers to get off 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
    public void unloadPassengers() 
    { 
//  for(int i = 0; i<passengers.getLength() && !trainInStation.trainHasReachedCapacity(); i++) 
//  { 
//   trainInStation.boardTrain(passengers.dequeue()); 
//  } 
     while(!passengers.isEmpty() && trainInStation.getCapacity()>numOfPassengers) 
     { 
      Passenger temp = dequeuePassenger(); 
      System.out.println(temp.toString() + " got on train " + this.trainInStation.trainType.getName()); 
      trainInStation.boardTrain(temp); 
     } 
    } 
} 

이 프로그램의 실행 제어는 열차와 스테이션 개체간에 .wait(); 및 .notify(); 스레딩을 처리하는 훨씬 더 우아한 방법이 있다는 느낌이 들었습니다 ... 왜 .notify()에 모니터가 있습니까? 내 경우 스레딩을 처리하는 더 좋은 방법이 있습니까? 이것들이 어리석은 질문이라면 미안합니다.

답변

2
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at Station.run(Station.java:37) 
    at java.lang.Thread.run(Unknown Source) 

이 해당 객체에 대한 synchronized 블록 내부없이 객체에 통지 요구하고 있음을 말하려고한다. 그것은 여기에있을 수 있습니다

stationBoarded.notify(); 

당신은 같은과 동기화해야합니다 : 어디든 당신이 notify() 또는 notifyAll() 전화를 기본적으로

trainInStation.notify(); // notify the train to let the passengers off 
... 
trainInStation.notify();//notify the train to depart 

:

synchronized (stationBoarded) { 
    stationBoarded.notify(); 
} 

아니면 이들 중 하나 .

1

wait() 호출을 중심으로 동기화 된 블록을 추가해야합니다.

1

개체에 대한 잠금을 먼저 얻지 않고 개체에 알림 또는 대기를 할 수 없습니다.

Station.java에서 run() 메소드에서 trainStation.notify()를 호출하고 있지만 코드 블록이 trainStation과 동기화되지 않았습니다.

호출 대기 또는 알림을 호출 대상 객체와 동기화하는 코드 블록을 동기화하거나 기다리면 즉각적인 문제가 없어집니다.

관련 문제