views:

183

answers:

1

I want to have such kind of work flow using explicit lock/condition variables (It's a course project which mandates this style.): A is the main class, it asks B to do some job from time to time. B has a worker class C which constantly queries B about new jobs to do and do it. After C finishes, it will call A's callback function to notify A the job is done.

However when I try to run the program, I get an IllegalMonitorStateException, when the callback() is trying to notify the doit() function.

exception in thread "Thread-0" java.lang.IllegalMonitorStateException
        at java.lang.Object.notifyAll(Native Method)
        at Test$A.callback(Test.java:49)
        at Test$C.run(Test.java:115)

I looked at the javadoc and some Q&A about this exception, but still no idea why I get this.

import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;

public class Test {
    public class A
    {
        private ReentrantLock lock;
        private Condition cond;
        private boolean bool;
        private B b;
        public A()
        {
            this.lock = new ReentrantLock();
            this.cond = lock.newCondition();
            b = new B(this);
            bool = false;
        }

        public void doit()
        {
            try {
                lock.lock();
                b.letgo();
                while (!bool) {
                    System.out.println("A::doit() Block.");
                    cond.awaitUninterruptibly();
                }
                System.out.println("A::doit() Done.");
            }
            finally {
                lock.unlock();
            }
        }

        public void callback() {
            try {
                lock.lock();
                bool = true;
                cond.notify();
                System.out.println("A::callback() done.");
            }
            finally {
                lock.unlock();
            }
        }
    }

    public class B
    {
        private C c;
        private ReentrantLock lock;
        private Condition cond;
        private boolean bool;
        public B(A a)
        {
            this.lock = new ReentrantLock();
            this.cond = lock.newCondition();
            bool = false;
            c = new C(a, this);
            c.start();
        }

        public void letgo()
        {
            try {
                lock.lock();
                bool = true;
            }
            finally {
                lock.unlock();
            }
        }

        public void get()
        {
            try {
                lock.lock();
                while (!bool) {
                    cond.awaitUninterruptibly();
                }
                bool = false;
                return;
            }
            finally {
                lock.unlock();
            }
        }
    }

    public class C extends Thread
    {
        private A a;
        private B b;

        public C(A a, B b)
        {
            this.a = a;
            this.b = b;
        }

        public void run()
        {
            while (true) {
                b.get();
                a.callback();
            }
        }
    }

    public static void main(String args[])
    {
        Test t = new Test();
        t.test1();
    }

    public void test1()
    {
        A a = new A();
        a.doit();
    }
}
+2  A: 

Use the signal() method on Condition in place of notify().

While you can successfully synchronize on a Condition instance, and then use the traditional wait() and notify() methods, you might as well just use an Object if you aren't using the extended capabilities of the concurrent classes.

Condition was intended to be used with the equivalent methods await() and signal(), and their enhanced variants.

erickson
I just found it myself... thanks for the quick answer!
CyberSnoopy