0

Gatesを船にシミュレートするプログラムがあります。それらはスレッドで実行されます。アイデアは、人が通過することをシミュレートするために、実行メソッドでランダムな瞬間にそれらを実行および一時停止させることです。これはすべてのスレッドによって行われますが、メインスレッドは通知を待っており、ゲートを通過する人を追加したことをスレッドが通知すると、船が満員かどうかを確認します。メインスレッドは、船が満員かどうかを再度確認します。プログラムには次の 3 つのクラスがあります。

カウンター:

    public class Counter {
        private int currentValue[];
        private int maxValue;

        public Counter(int[] nrOfPeople, int max) {
            currentValue = nrOfPeople;
            currentValue[0] = 0;
            maxValue = max; 
        }

        public synchronized void addPersons(int nr_p) {
            currentValue[0] += nr_p;
        }

        public synchronized int getValue() {
            return currentValue[0];
        }

        public synchronized boolean isFull() {
            if(currentValue[0] < maxValue)
                return false;
            return true;
        }
    }

ゲートクラス:

    public abstract class Gate implements Runnable {
        int nrOfPassengers;
        int gatenr;
        int gatesize;
        Counter c;
        private Thread t;
        private Random r;
        private boolean blocked; /* suspends people from passing */

        public Gate(Counter c, int nr) {
            this.c = c;
            gatenr = nr;
            this.open();
            r = new Random();
            t = new Thread(this);
            t.start();
        }

        public void setGatesize(int size) {
            gatesize = size;
        }

        public void close() {
            blocked = true;
        }

        public void open() {
            blocked = false;
        }

        public int getNoOfPassangers() {
            return nrOfPassengers;
        }

        public int getId() {
            return gatenr;
        }

        @Override
        public void run() {
            while(!blocked) {
                int waitTime = (r.nextInt(5) + 1) * 1000; /* between 1-5 seconds */
                System.out.println("Person-Gate " + gatenr + ": adding one to " + c.getValue());
                try {
                    /* bigger throughput => amount can vary */
                    if(gatesize > 1) {
                        int persons = r.nextInt(gatesize)+1;
                        c.addPersons(persons);
                        nrOfPassengers += persons;
                    } else {
                        c.addPersons(1);
                        nrOfPassengers++;
                    }
                    Thread.sleep(waitTime);
                } catch (InterruptedException e) {
                    System.out.println("Person-Gate " + gatenr + ": was interrupted adding person");
                    e.printStackTrace();
                }
                System.out.println("Person-Gate " + gatenr + ": added one to " + c.getValue());
                t.notify();
            }
        }

        public void join() {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

そして、main メソッドを実行するシミュレーター:

    /*
     * This class simulates cars and persons- entering a ferry.
     */
    public class Simulator {

        public static final int MAX = 30;

        public static void main(String[] args) {
            int nrOfPeople[] = new int[1]; /* array of size one for keeping count */
            ArrayList<Gate> gates = new ArrayList<Gate>();
            Counter counter = new Counter(nrOfPeople, MAX);
            Thread mainThread = Thread.currentThread();

            /* adding 3 person-gates */
            for(int i=1; i<4; i++) {
                gates.add(new PersonGate(counter, i));
            }

            /* let all gates work as long as passengers is under MAX */
            while(!counter.isFull()) { 
                try {
                    mainThread.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println("Announcement: Ship is full!");

            /* wait for child threads to finish */
            for(Gate g: gates) {
                g.close();
                try {
                    g.join();
                } catch (Exception e) { /* InterruptedException */
                    e.printStackTrace();
                }
                System.out.println(g.getNoOfPassangers() + " passed through gate nr " + g.getId());
                System.out.println(counter.getValue() + " has passed in total");
            }

        }
    }

エラーが発生します

Person-Gate 1: adding one to 0
Person-Gate 2: adding one to 1
Person-Gate 3: adding one to 2
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at Simulator.main(Simulator.java:24)
Person-Gate 3: added one to 3Exception in thread "Thread-3" 

誰かが今何が起こっているのですか?

4

3 に答える 3

0
 t.notify();

間違ったモニターを通知しています。synchronizeこの例外は、モニター オブジェクトをセクションでラップしない場合に発生します。ただし、通知メソッドと待機メソッドに使用しているオブジェクトは異なります。モニターを作成new Object()し、Gate のコンストラクターに渡します。

また、あなたがCountDownLatch達成しようとしていることを正確に実行します。

于 2013-03-27T12:00:16.910 に答える
0

wait または notify を呼び出すオブジェクトのモニターを所有している必要があります。つまり、次のように同期ブロックにいる必要があります

synchronized( objectUsedAsSynchronizer) {
    while ( mustStillWait) {
        objectUsedAsSynchronizer.wait();
    }
}

これは、他の多くの質問の対象となっています。

于 2013-03-27T11:55:59.693 に答える