【问题标题】:java.lang.IllegalMonitorStateException in Monitor class of dining philosophersjava.lang.IllegalMonitorStateException 在 Monitor 类的餐饮哲学家
【发布时间】:2015-04-08 23:10:38
【问题描述】:

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

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 来唤醒监视器。但这并不重要。并且,当我们在条件变量上使用等待时,在拾取方法中发生监视器异常。为什么?因为他们都使用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)

我更新了代码并删除了额外的类,所以都在一个类中,也许现在更清楚该错误在哪里

【问题讨论】:

  • 请给出异常的完整堆栈跟踪,这通常是调试的第一步
  • 不要将同步和 java.util.concurrent. 混在一起,那样很疯狂。
  • 是的,但它无论如何都不起作用

标签: java exception condition-variable monitors


【解决方案1】:

你做错了很多事情。

  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。两者都不是。

【讨论】:

  • 如果你在发信号之前做(1),它会正常工作。
  • @flup 使用 PhilosopherCard.lock.lock(); 将同步 OP 需求
  • @Ophelia 我知道问题出在哪里,但我想给你足够的信息让你自己得出结论。我将编辑我的答案以提供更多信息。
  • @Ophelia 你能把问题中的代码更新到现在的样子吗?
  • @Ophelia 抱歉,刚回来。真高兴你做到了。从现在开始,您对完成的工作有任何疑问吗?
猜你喜欢
  • 2016-03-04
  • 1970-01-01
  • 2013-01-28
  • 2019-02-07
  • 1970-01-01
  • 1970-01-01
  • 2010-10-26
  • 1970-01-01
  • 2016-06-17
相关资源
最近更新 更多