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

java.lang.IllegalMonitorStateException in Monitor class of dining philosophers

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

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 中我们可以通过 self[index].signal 来唤醒显示器。但这并不重要。并且,当我们在条件变量上使用等待时,在 pickup 方法中发生监视器异常。为什么?因为他们都用一把锁? 所有踪迹

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)

我更新了代码并删除了额外的 class,所以一切都合而为一 class,也许现在更清楚错误在哪里了

你有很多地方做错了。

  1. 您在 this 上处于 synchronizing,但未锁定 PhilosopherCard.lock。通过锁定,我的意思是 PhilosopherCard.lock.lock();
  2. 您正在使用 wait 而不是 await

更新以获取更多信息

如果您查看您的这段代码并删除 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。两者都不是。