0

I'm currently working on an Airport app with 2 lanes, but I have a problem with the planes landing. If there is only one lane working everything works fine but if I add a lane, the planes land one at a time, when they should be landing on both the lanes at the same time. I've tried using System.out to see where the problem was but, that was of little help. If you guys could help me see what I'm doing wrong I would be very thankful. Thanks and here is the relevant code(I know it's a bit much):

public class Airport{ 


    private List<Lane> lanesOpen = new ArrayList<Lane>();
    private List<AirplaneThread> airplanes;

    public void start(){
        for(AirplaneThread airplane : airplanes){
            if(airplane.getState()==Thread.State.NEW)
                airplane.start();
        }
    }

    public void open(List<AirplaneThread> airplanes) {
        this.airplanes = airplanes;
    }

    public synchronized void requestLane(){
        while(getLanesAvailable().size()==0 && airplanes.size()==0 ){
            try {
                wait();
            } catch (InterruptedException e) {     }
        }
        List<Lane> lanes = getLanesAvailable();
        for(Lane lane: lanes){
            if(airplanes.size()>0){
                AirplaneThread airplane = airplanes.remove(0);
                airplane.land(lane);
            }
        }
        notifyAll();
    }

    public synchronized void landingIsOver(Lane lane){
        while(!lane.isClear()){
            try{
                wait();
            }catch(InterruptedException e){
            }
        }
        lane.getText().setText("");
        notifyAll();
    }

    public List<Lane> getLanesAvailable(){
        List<Lane> lanes = new ArrayList<>();
        synchronized(lanesOpen){
        for(Lane l : lanesOpen){
            if(l.isClear())
                lanes.add(l);
        }
        }
        return lanes;
    }

    public void addLaneOpen(Lane lane){
        synchronized(lanesOpen){
        lanesOpen.add(lane);
        }
    }

    public void removeLane(Lane l){
        synchronized(lanesOpen){
        Iterator<Lane> iterator = lanesOpen.iterator();
        while(iterator.hasNext()){
            Lane lane = iterator.next();
            if(lane.getNumber()==l.getNumber())
                iterator.remove();
        }
    }
}


public class AirplaneThread extends Thread implements AirplaneModel {

    protected final String name;
    protected final int capacity;
    protected int fuel;
    protected final int consumption;
    protected boolean hasLanded;
    protected final int LANDING_TIME;
    protected Airport airport;

    public AirplaneThread(String name, int capacity, int fuel, int consumption, int LANDING_TIME, Airport airport){
        this.name = name;
        this.capacity = capacity;
        this.fuel = fuel;
        this.consumption = consumption;
        this.LANDING_TIME = LANDING_TIME;
        this.hasLanded = false;
        this.airport = airport;
    }


    @Override
    public void run() {
        while(!hasLanded){
            airport.requestLane();
        }
    }


    public synchronized void land(Lane lane){
        try{
            lane.changeState(false);
            lane.getText().setText(toString());
            airport.notifyOut(3);
            sleep(LANDING_TIME);
            hasLanded = true;
            lane.changeState(true);
            airport.landingIsOver(lane);
        }catch(InterruptedException e){   }
    }
}

public class Lane {

    private JTextField plane;
    private JCheckBox open;
    private boolean isclear;
    private int number;

    public Lane(JTextField plane, JCheckBox open, JLabel label, int number){
        this.plane = plane;
        this.open = open;
        this.isclear = false;
        this.number = number;
    }

    public void changeState(boolean state){
        this.isclear = state;
    }

    public boolean isClear(){
        return isclear;
    }
}

And i also have this code for a sentinel whenever i open a lane in my GUI:

 laneB.addActionListener(new ActionListener() {
 @Override
 public void actionPerformed(ActionEvent e) {
      //basically this returns the lane which checkbox i clicked
        Lane lane = CenterPanel.getLanes().get(j-1);
        if(lane.getCheck().isSelected()){
            airport.removeLane(lane); 
            lane.close(); 
        }else{ 
            lane.open();
            airport.start();
            airport.addLaneOpen(lane);
        }
        }
    });     
Wojciech Wirzbicki
  • 3,887
  • 6
  • 36
  • 59
GamerGirl
  • 55
  • 8
  • 1
    To quote Brian Goetz: "Writing concurrent programs is more difficult than writing single-threaded programs because there are more things that can go wrong and errors can be much more difficult to detect." – scottb Dec 07 '16 at 22:17

1 Answers1

0

In some methods you synchronize on the Airport instance, in other methods you use the lanesOpen object. This way for example a wait in requestLane method will get never notified if you add a lane with addLaneOpen. I think you should synchronize simply on the Airport object everywhere, and add notify to the method, where a lane is added.

Generally you can simply find out what your problem is, if you get a threaddump (using your IDE, jstack or jvisualvm). You will see, what threads you have, which are waiting on what kind of Object. Then you will find your bug immediately.

Gábor Lipták
  • 9,646
  • 2
  • 59
  • 113