多线程。明确的锁和条件

时间:2015-08-12 10:00:27

标签: java multithreading conditional-statements explicit locks

我很难理解多线程。不幸的是,这是我需要提交的作业之一才能通过该课程。

这是关于火车的: - 火车等待乘客线程派遣一些乘客,直到达到容量。

  • 然后火车去兜风。在此期间,没有乘客登上火车。

  • 下一步是取消操作,这是Passenger线程调用的过程。

  • 一旦发生这种情况,周期将与其他乘客一起继续。

我在unboarding部分遇到了麻烦,有时候我会得到一个超出界限的异常。

这是错误:

乘客3登上了火车 乘客0已登上火车 乘客1登上了火车 乘客12登上了火车 乘客13登上了火车 火车满车             座位:0乘客:3
            座位:1名乘客:0人             座位:2名乘客:1人             座位:3名乘客:12人             座位:4名乘客:13人 骑行开始
骑行结束
乘客3想下车。座位:0
    乘客:火车下车3             乘客离开:0
            乘客离开:1
线程“Thread-16”中的异常java.lang.ArrayIndexOutOfBoundsException:-1
    at java.util.ArrayList.elementData(Unknown Source)
    at java.util.ArrayList.remove(Unknown Source)
    在parque.Train.unboardTrain(Train.java:104)
    在parque.Passenger.run(Passenger.java:23)
            乘客离开:12
            乘客离开:13
乘客15想要下车。座位:-1 //没有乘客ID 15,嗯?

我想知道如何避免这种异常?我想是可能实施另一个与火车锁分开的锁,那将负责门,或者这应该作为条件实施?,帮助请

以下是代码:

public class Train extends Thread {
    private int id;
    private int capacity;
    private ArrayList<Integer> passengers;
    private Lock l = new ReentrantLock();
    private Condition trainFull = l.newCondition();
    private Condition boardTrain = l.newCondition();
    private Condition UnboardTrain = l.newCondition();
    private boolean canBoard = true;
    private boolean canUnboard = false;



//se definen los constructores  
    public Train(int id, int capacity) {
        this.id = id;
        this.capacity = capacity;
        this.passengers = new  ArrayList<Integer>(capacity);

    }//fin constructor  
    public Train(int id) {
        this.id = id;
        this.capacity = 5;
        passengers = new  ArrayList<Integer>(capacity);

    }//fin constructor

    public void boardTrain(int passengerId)  {
        l.lock();

        try{
            while(!canBoard)
                boardTrain.await();
                if (passengers.size() == capacity) {
                    canBoard = false;
                    trainFull.signal();
                } else {
                    passengers.add(passengerId);
                    System.out.println("Passenger " + passengerId +" has boarded the train");
                }//if

        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Exception at boarding");
        }finally{
            l.unlock();
        }//try


    }//fin subir

    public void waitsFullTrain() {     //waits until n (capacity) passengers board the train
        l.lock();

        try{
            trainFull.await();

            System.out.println("TRAIN FULL");
            for(int i = 0; i< passengers.size(); i++){
                System.out.println("            SEAT: " + i + " Passenger: " + passengers.get(i));
            }//for
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            l.unlock();
        }//try


    }//fin esperaLleno

    public void goForRide() throws InterruptedException{

        l.lock();
        try{
            System.out.println("RIDE STARTS");
            Thread.sleep(2000);
            System.out.println("RIDE ENDS");
            canUnboard = true;
            UnboardTrain.signalAll();       

        }finally{
            l.unlock();
        }       

    }//fin darVuelta


    public void unboardTrain(int pasajeroId) {
        l.lock();

        try{
            while(!canUnboard)
                UnboardTrain.await();
            //System.out.println("Bajando..");
            if(passengers.size() >0){
                System.out.println("Passenger "+ pasajeroId + " wants to get off the train. SEAT: "+passengers.indexOf(pasajeroId) );
                passengers.remove(passengers.indexOf(pasajeroId));
                System.out.println("    Passenger: " + pasajeroId + " off the train");

                for (int i = 0; i<passengers.size();i++){
                    System.out.println("            Passenger(s) left: "+passengers.get(i));
                }
            }else{
                System.out.println();
                canUnboard = false;
                canBoard = true;
                boardTrain.signalAll();         
            }//if
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Exception at unboarding");
        }finally{
            l.unlock();
        }//try


    }//fin bajar



    public int id() {
        return id;
    }//fin id

    @Override
    public void run() {
        while(true){
            this.waitsFullTrain();
            try {
                this.goForRide();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }//fin while    

    }//fin run


}//fin clase


public class Passenger extends Thread{

    private int id;
    private Train t;

    public Passenger(int id, Train t) {
        this.id = id;
        this.t = t;
    }

    @Override
    public void run() {

        t.boardTrain(this.id);
        t.unboardTrain(this.id);

    }//run
}//Passenger


public class Main {

    public static void main(String[] args) {

        Train t = new Train(1);
        Passenger[] p = new Passenger[20];

        for (int i = 0; i < p.length; i++) {
            p[i]= new Passenger(i, t);
        }//for
        t.start();

        for (int i = 0; i < p.length; i++) {
            p[i].start();
        }//for

        try {
            t.join();
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        for (int i = 0; i < p.length; i++) {
            try {
                p[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }//for
    }//main
}//clase

2 个答案:

答案 0 :(得分:0)

问题是有些乘客在没有列车的情况下试图挂机。在&#39; boardTrain&#39;中查看您的代码并包含以下更改以更好地了解您的问题(当乘客无法进入火车时,请参阅新消息):

if (passengers.size() == capacity) {
    System.out.println("Passenger " + passengerId + " CANNOT board the train =>  TRAIN FULL");
    canBoard = false;
    trainFull.signal();
} else {
    passengers.add(passengerId);
    System.out.println("Passenger " + passengerId +" has boarded the train");
}

现在执行你的代码几次。当你再次收到错误时,你会看到哪个乘客没有进入火车(你也可以在你的踪迹中看到它,因为没有关于乘客15进入火车的任何消息)。

接下来会发生什么?登上火车后,乘客试图取消火车:

t.boardTrain(this.id);
t.unboardTrain(this.id);
但是,如果没有进入火车的乘客试图登机,会发生什么?您将收到如下消息:

  

乘客15想要下车。座位:-1

然后代码继续执行以下行:

passengers.remove(passengers.indexOf(pasajeroId));

并抛出异常,因为&#39; passengers.indexOf(pasajeroId)&#39;值为-1,正如您在文档中看到的那样,-1不是有效的索引:http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#remove(int)

尝试使用&#39; boardTrain&#39;返回一个布尔值。方法,只有在乘客上火车的情况下才能登机。

我希望这会有所帮助;)。 Suerte。

答案 1 :(得分:0)

好的,所以在玩完这个东西之后,这是正确的实施,万一有人可能需要它:

最后,诀窍是在乘客登机后检查火车是否已满。我允许下一位乘客进入boardTrain方法,然后检查容量,如果已满,拒绝该乘客,但该乘客“丢失”,这就是我在unboard方法和ArrayIndexOutOfBoundsException中出现小问题的原因:-1。

public class Train extends Thread {
    private int id;
    private int capacity;
    private ArrayList<Integer> passengers;
    private Lock l = new ReentrantLock();
    private Condition trainFull = l.newCondition();
    private Condition boardTrain = l.newCondition();
    private Condition unboardTrain = l.newCondition();
    private boolean canBoard = true;
    private boolean canUnboard = false;



//se definen los constructores  
    public Train(int id, int capacity) {
        this.id = id;
        this.capacity = capacity;
        this.passengers = new  ArrayList<Integer>(capacity);

    }//fin constructor  
    public Train(int id) {
        this.id = id;
        this.capacity = 5;
        passengers = new  ArrayList<Integer>(capacity);

    }//fin constructor

    public void boardTrain(int passengerId)  {
        l.lock();

        try{
            while(!canBoard)
                boardTrain.await();
            passengers.add(passengerId);
            System.out.println("Passenger: " + passengerId +" has boarded the train");

            if (passengers.size() == capacity) {  //<------this here did the trick!
                canBoard = false;
                trainFull.signalAll();
            }


        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Exception at boarding");
        }finally{
            l.unlock();
        }//try


    }//fin subir

    public void waitsFullTrain() {     //waits until n (capacity) passengers board the train
        l.lock();

        try{
            trainFull.await();
                        System.out.println("TRAIN FULL");
            for(int i = 0; i< passengers.size(); i++){
                System.out.println("            SEAT: " + i + " Passenger: " + passengers.get(i));
            }//for
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            l.unlock();
        }//try


    }//fin esperaLleno

    public void goForRide() throws InterruptedException{

        l.lock();
        try{
            System.out.println("RIDE STARTS");
            Thread.sleep(2000);
            System.out.println("RIDE ENDS");
            canUnboard = true;
            unboardTrain.signal();      

        }finally{
            l.unlock();
        }       

    }//fin darVuelta


    public void unboardTrain(int pasajeroId) {
        l.lock();

        try{
            while(!canUnboard)
                unboardTrain.await();
            //System.out.println("Bajando..");

            if(passengers.size() >0){
                if(passengers.indexOf(pasajeroId) > -1){
                    System.out.println("Passenger "+ pasajeroId + " wants to get off the train. SEAT: "+passengers.indexOf(pasajeroId) );
                    passengers.remove(passengers.indexOf(pasajeroId));
                    System.out.println("    Passenger: " + pasajeroId + " off the train");
                    if(passengers.size() ==0){
                        System.out.println();
                        canUnboard = false;
                        canBoard = true;
                        boardTrain.signalAll();                         
                    }else{
                        unboardTrain.signal();
                        System.out.print("      Remaining passengers: ");
                        for (int i = 0; i<passengers.size();i++){
                            System.out.print(" "+passengers.get(i));
                        }//for
                    }


                }else{
                    unboardTrain.signal();
                }//if
            }else{
                System.out.println();
                canUnboard = false;
                canBoard = true;
                boardTrain.signalAll();         
            }//if
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Exception at unboarding");
        }finally{
            l.unlock();
        }//try


    }//fin bajar



    public int id() {
        return id;
    }//fin id


    public void run() {
        while(true){
            this.waitsFullTrain();
            try {
                this.goForRide();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }//fin while    

    }//fin run


}//fin clase