【问题标题】:Multithread. Explicit locks and conditions多线程。显式锁和条件
【发布时间】:2015-11-04 20:52:48
【问题描述】:

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

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

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

  • 下一步是下机,这是一个由Passenger线程调用的过程。

  • 一旦发生这种情况,其余乘客将继续循环。

我在卸载部分遇到问题,有时我会遇到数组越界的异常。

这是错误:

乘客 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
在 java.util.ArrayList.elementData(未知来源)
在 java.util.ArrayList.remove(未知来源)
在 parque.Train.unboardTrain(Train.java:104)
在 parque.Passenger.run(Passenger.java:23)
剩余乘客:12
离开的乘客:13
乘客 15 想下车。 SEAT: -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

【问题讨论】:

  • 请发布堆栈跟踪。
  • 在我看来,这个设计中的模型有点不对劲。想想现实世界......当车门关闭或火车不在车站时,乘客无法上下车(那些应该是你的锁)。当门打开时,unboard(), board()... 当超时发生时,关门 & 火车出发。
  • 你忘了问问题!问一个实际的、具体的问题真的很重要。这就是为什么您按下的按钮被标记为
  • 谢谢戴夫,我会尝试使用你的建议。
  • 对不起,大卫,已经纠正了,干杯

标签: java multithreading conditional-statements explicit locks


【解决方案1】:

问题在于,有些乘客实际上不在火车内,却试图下车。查看您在“boardTrain”中的代码并包含以下更改,以便更好地了解您的问题(当乘客无法上车时,请参阅新消息):

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));

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

尝试使用您的“boardTrain”方法返回一个布尔值,并且仅在乘客登上火车时下车。

我希望这会有所帮助;)。苏尔特。

【讨论】:

  • 您指出的错误是正确的,但解决方案应该是,乘客应该等待,直到他可以真正上车。
  • BitExodus 非常感谢您指出这一点,我没有想到那些无法上车的乘客。遗憾的是无法更改返回类型,但会尝试找出一种只有登上火车的人才能下车的方法,谢谢!
  • @xeed 这是一个选项,我想这取决于问题定义。乘客可能会等待上火车或离开车站,谁知道呢。很公平。
【解决方案2】:

好的,所以在玩弄了这个东西之后,这是正确的实现,以防万一有人需要它:

最后,诀窍是在乘客上车后立即检查火车是否已满。我允许下一位乘客进入 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    • 2017-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多