0

I am new to monitors and condition variables. I am using lock and condition variables in my monitor.

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

        // ...
    }


}

In putdown we can self[index].signal to wake up monitors. But it is not that important. And, in pick up method monitor exception occurs, when we use wait on condition variable. Why? Because they all use 1 lock? All trace

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)

I updated the code and removed extra class, so all in one class, maybe now it is more clear where can be that error

Ophelia
  • 549
  • 1
  • 5
  • 26

1 Answers1

2

There are a number of things you're doing wrong.

  1. You are synchronizing on this and not locking on PhilosopherCard.lock. By locking, I mean PhilosopherCard.lock.lock();
  2. You are using wait instead of await.

Update for more information

If you take a look at this code of yours and remove synchronized the code won't fail.

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

Where you signal it is similar to await, but without synchronized why wouldn't it throw an IMSE? That's because you are holding the PhilosopherCard.lock lock. If you removed those two locks you would get an IMSE.

You are running into that issue in pickUp. I would remove synchronized from the method all together. Why? Because you are mixing synchronization. If you want to do synchronization with synchronized that's fine, but if you're doing synchronization with java.util.concurrent.Lock then you cannot use synchronized.

The synchronized keyword can allow you to use wait, notify and notifyAll on the object.

The j.u.c.Lock and j.u.c.Condition allow you to use await, signal, signalAll. So my suggestion is either use only Lock/Condition or synchronized. Not both.

John Vint
  • 39,695
  • 7
  • 78
  • 108
  • 1
    If you do (1) before signaling, it will work correctly. – John Vint Apr 08 '15 at 23:19
  • He's right, conditons require await(). But to make the IllegalMonitorStateException go away, you'll need to synchronize on the proper object first. – flup Apr 08 '15 at 23:21
  • 2
    @flup Using `PhilosopherCard.lock.lock();` will do the synchronizing the OP needs – John Vint Apr 08 '15 at 23:22
  • You're right, I thought the question was about synchronized/wait but it's more about lock() and await(). – flup Apr 08 '15 at 23:28
  • i removed philosopher card, all in one class, maybe now it is more obvious what can it be/ – Ophelia Apr 08 '15 at 23:37
  • 2
    @Ophelia I know what the problem is but am trying to give you enough information to come to the conclusion on your own. I'll edit my answer to give more information. – John Vint Apr 08 '15 at 23:46
  • that is correct, i dont really need synchronization there. but if remove that i still have this:Exception in thread "Thread-2" java.lang.IllegalMonitorStateException at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(Unknown Source) at Monitor.test(Monitor.java:67) at Monitor.pickUp(Monitor.java:81) at Philosopher.run(Philosopher.java:95) – Ophelia Apr 09 '15 at 00:10
  • @Ophelia Did you remove `synchronized` or `PhilosopherCard.lock.lock();` – John Vint Apr 09 '15 at 00:12
  • 1
    @Ophelia can you update your code in the question to how it is now? – John Vint Apr 09 '15 at 00:35
  • 1
    @Ophelia Sorry, just got back to it. Glad you got it working. Do you have any questions from this point on from what you finished with? – John Vint Apr 09 '15 at 16:25