让我了解Java线程,监视器等....

时间:2012-03-06 17:19:18

标签: java multithreading thread-safety

我正在开展一个项目,我需要进行圆形和螺纹加工来模拟火车接送乘客。我使用Object.notify和Object.wait来控制线程。我是Threading应用程序的新手,我收到了这个我不明白的错误:

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()有一个监视器?在我的情况下,有更好的方法来处理线程吗?对不起,如果这些都是愚蠢的问题。

3 个答案:

答案 0 :(得分: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)

这是试图告诉您正在调用对象上的notify,而不是在该对象的synchronized块内。它可能在这里:

stationBoarded.notify();

您需要将其与以下内容同步:

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

或者其中一个:

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

您可以在任何地方致电notify()notifyAll()

答案 1 :(得分:1)

您需要在wait()调用周围添加一个synchronized块。

答案 2 :(得分:1)

如果没有先获取对象的锁定,则无法调用通知或等待对象。

在Station.java中,您在run()方法中调用trainStation.notify(),但代码块未与trainStation同步。

将调用wait或notify的代码块与您正在调用的对象进行同步或通知,并立即解决您的问题。