用餐哲学家的Monitor类中的java.lang.IllegalMonitorStateException

时间:2015-04-08 23:10:39

标签: java exception condition-variable monitors

我是监视器和条件变量的新手。我在我的监视器中使用锁定和条件变量。

public class Monitor  
{   
    private final int piNumberOfPhilosophers;
    private PhilosopherCard[] self;
    private Integer[] names;
    private int invited = 0;
    static Lock lock = new ReentrantLock();
    private Condition[] status; // = lock.newCondition();
    private String[] state;
    /**
     * Constructor
     */
    public Monitor(int piNumberOfPhilosophers)
    {        this.piNumberOfPhilosophers = piNumberOfPhilosophers;         

        self = new PhilosopherCard[this.piNumberOfPhilosophers];
        names = new Integer[this.piNumberOfPhilosophers];
        status = new Condition [this.piNumberOfPhilosophers];
        state = new String [this.piNumberOfPhilosophers];
        //Arrays.asList(state).indexOf(4);      
        }

    public void invitePhilosopher (int id){

        names[invited] = id;
        System.out.println(invited);
        PhilosopherCard philosopher = new PhilosopherCard("thinking");
        self[invited] = philosopher;
        status[invited] =lock.newCondition();
        state[invited] = "thinking";
        invited++;
        }           
    /**
     * check other philosophers (<_<) - > (0_o) -> (>_>)
     */

    private void  test (int index){
        lock.lock();

        int left = index-1;
        int right = index +1;
        if(index==0){
            left=piNumberOfPhilosophers-1;
        }
        if(index == piNumberOfPhilosophers-1){
            right = 0;
        }
        if((state[left]!="eating")&(state[right]!="eating")){
            state[index]="eating";
            status[index].signal();
            }
        lock.unlock();

    }


    public void pickUp(final int piTID) throws InterruptedException
    {        
        int index = Arrays.asList(names).indexOf(piTID);    
        state[index]="hungry";
        test(index);
        if(!state[index].equals("eating")){     
                status[index].wait();
        }   
    }

    /**
     * When a given philosopher's done eating, they put the chopstiks/forks down
     * and let others know they are available.
     */
    public void putDown(final int piTID)
    {   
        int index = Arrays.asList(names).indexOf(piTID);
        self[index].setState("thinking");

        int left = index-1;
        int right = index +1;
        if(index==0){
            left=piNumberOfPhilosophers-1;
        }
        if(index == piNumberOfPhilosophers-1){
            right = 0;
        }
        test(left);
        test(right);

        // ...
    }


}

在putdown中,我们可以自我[索引] .signal唤醒监视器。但它并不重要。并且,在拾取方法监视器异常发生时,我们在条件变量上使用wait时。为什么?因为他们都使用1锁? 全部跟踪

Exception in thread "Thread-1" Exception in thread "Thread-3" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Unknown Source)
    at Monitor.pickUp(Monitor.java:75)
    at Philosopher.run(Philosopher.java:95)
java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Unknown Source)
    at Monitor.pickUp(Monitor.java:75)
    at Philosopher.run(Philosopher.java:95)

我更新了代码并删除了额外的类,所以在一个类中,也许现在可以更明确的是哪个错误

1 个答案:

答案 0 :(得分:2)

有很多事情你做错了。

  1. synchronizing上的this并未锁定PhilosopherCard.lock。通过锁定,我的意思是PhilosopherCard.lock.lock();
  2. 您使用wait代替await

  3. 更新以获取更多信息

    如果您查看自己的代码并删除synchronized,代码就会失败。

       private void test (int index){
            PhilosopherCard.lock.lock();
            int left = index-1;
            int right = index +1;
            if(index==0){
                left=piNumberOfPhilosophers-1;
            }
            if(index == piNumberOfPhilosophers-1){
                right = 0;
            }
            if((state[left]!="eating")&(state[right]!="eating")){
                state[index]="eating";
                status[index].signal();;
                }
            PhilosopherCard.lock.unlock();
        }
    

    signal的位置与await相似,但没有同步,为什么它不会引发IMSE?那是因为你持有 PhilosopherCard.lock锁定。如果您删除了这两个锁,您将获得IMSE。

    您正在pickUp遇到该问题。我会一起从方法中删除synchronized。为什么?因为你正在混合同步。如果您希望与synchronized进行同步,但如果您与java.util.concurrent.Lock进行同步,则无法使用synchronized

    synchronized关键字可以让您在对象上使用waitnotifynotifyAll

    j.u.c.Lockj.u.c.Condition允许您使用awaitsignalsignalAll。因此,我的建议是仅使用Lock / Conditionsynchronized。不是两个。