简体   繁体   中英

wait() or notifyAll() creating infinite loop

I have a program which simulates an Airport which is based on the code found here: http://www.javapractices.com/topic/TopicAction.do?Id=51

Which has three classes: Airport, Airplane and AirportSimulator (in my case) and uses threads to synchronise actions.

The problem I'm having is that when the airplane is waiting for runway space for landing, the notifyAll() function doesn't seem to be working, and as such the airplane stays in an infinite loop of "waiting" for space.

I think the problem lies with either the wait() being infinite due to not being interrupted, or the notifyAll() not working and notifying the threads (airplanes) which are waiting on them.

Any help is appreciated.

EDIT: Here are the classes.

Airplane.java

public class Airplane implements Runnable
{
    public Airplane(Airport anAirport, String FlightID)
    {
        fAirport = anAirport;
        aFlightID = FlightID;
    }

    @Override
    public void run()
    {
        takeOff();
        fly();
        land();
    }

    //Private
    private Airport fAirport;
    private String aFlightID;

    private void takeOff()
    {
        synchronized(fAirport)
        {
            while(!fAirport.hasAvailableRunway())
            {
                System.out.println(aFlightID + ": waiting for runway space");
                try
                {
                    fAirport.wait();
                }
                catch(InterruptedException ex)
                {
                    System.err.println(ex);
                    Thread.currentThread().interrupt();
                }
            }
            System.out.println(aFlightID + ": departing now...");
        }
    }

    private void fly()
    {
        System.out.println(aFlightID + ": now flying...");
        try
        {
            //wait for 10 seconds
            Thread.sleep(10000);
        }
        catch(InterruptedException ex)
        {
            System.err.println(ex);
            Thread.currentThread().interrupt();
        }
    }

    private void land()
    {
        synchronized(fAirport)
        {
            while(!fAirport.hasAvailableRunway())
            {
                System.out.println(aFlightID + ": waiting for runway space");
                try
                {
                    fAirport.wait();
                }
                catch(InterruptedException ex)
                {
                    System.err.println(ex);
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
}

Airport.java

public class Airport implements Runnable
{

    public Airport(String aName)
    {
        super();
        fName = aName;
    }

    public synchronized boolean hasAvailableRunway()
    {
        return fHasAvailableRunway;
    }

    @Override
    public void run()
    {
        System.out.println("Running: " + fName + " Airport.");
        while(true)
        {
            try
            {
                synchronized(this)
                {
                    //Toggle runway state between available and unavailable
                    fHasAvailableRunway = !fHasAvailableRunway;
                    System.out.println(fName + " Has Available Runway: " + fHasAvailableRunway);
                    //Notify waiters of the state change
                    this.notifyAll();
                }
                Thread.sleep(2000); //Pause for a couple of seconds
            }
            catch(InterruptedException ex)
            {
                System.err.println(ex);
                Thread.currentThread().interrupt();
            }
        }
    }

    //Private
    private boolean fHasAvailableRunway = true;
    private String fName;

}

And finally, AirportSimulator.java

public class AirportSimulator 
{
    public static void main(String[] args)
    {
        System.out.println("Running Airport Simulation");

        //Create an airport and start running
        Airport leedsBradfordAirport = new Airport("Leeds & Bradford International");
        Thread airport = new Thread(leedsBradfordAirport);
        airport.start();

        //Create a plane and start running
        Thread airplaneOne = new Thread(new Airplane(leedsBradfordAirport, "Flight 2112"));
        //Thread airForceTwo = new Thread(new Airplane(leedsBradfordAirport, "Flight 1986"));
        airplaneOne.start();
        //airForceTwo.start();

        System.out.println("Terminating original thread");
    }
}

When I run your program, the Airplane thread does not hang: It calls takeOff(), fly(), and land(). After that it terminates...

...without printing any message.

Every time I run it, at the exact moment when it calls land(), the runway is available, so it never enters the while() loop, it never calls wait(). It just returns, and that's the end of the story.


Couple of comments:

Your program makes no attempt to keep more than one airplane from using "the runway" at the same time. I put in the scare quotes, because there really is no runway in your model. There is just a boolean flag, and whenever it is true, then every airplane that wants to take off or land is allowed to do so.

Your program sort-of handles InterruptedException, and sort-of does not. The language forced you to write handlers, and in each of your handlers, you carefully reset the interrupted flag, but then nothing ever tests the flag. In most real programs, an interrupt means "shut down gracefully." In that case, you want to test isInterrupted() in each of your loops, and clean-up and exit if it ever is true.

If you don't want to go to all that trouble, then you may as well just write:

} catch (InterruptedException ex) {
    throw new RuntimeException(ex);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM