Ali Dehkhodaei
Ali Dehkhodaei

Reputation: 444

lock and unlock in multi thread java

I use lock and unlock in the my code And start some Customer and Producer Thread. line lock.waite throws IllegalMonitorStateException.Why? With the lock, the conditions for using this list are not provided in one Thread?

 static class Customeer extends Thread {
            private List<String> list;
            private Lock lock;
            public Customeer(List<String> list, Lock lock) {
                this.list = list;
                this.lock = lock;
            }
            @Override
            public void run() {   
                lock.lock();
                if (list.size() == 0) {
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                    list.remove(0);
                    lock.unlock();
            }
        }
    
        static class Producer extends Thread {
            private List<String> list;
            private Lock lock;
            public Producer(List<String> list, Lock lock) {
                this.list = list;
                this.lock = lock;
            }
            @Override
            public void run() {
                    lock.lock();
                    list.add("hello");
                    list.notify();
                    lock.unlock();
            }
        }

Upvotes: 1

Views: 1061

Answers (2)

Dmitrii B
Dmitrii B

Reputation: 2860

You have some problems with your code, namely:

  1. list.wait(); you can't acquire the list's monitor unless you are within a synchronized method (or block code).

  2. list.notify();, you can't release the list's a monitor unless you are within a synchronized method (r block code).

You can't use .wait() or .notify() from none synchronized method or section.

Change your code like that snippet:

 static class Customeer extends Thread {
            private List<String> list;
            private Lock lock;
            public Customeer(List<String> list, Lock lock) {
                this.list = list;
                this.lock = lock;
            }
            @Override
            public void run() {   
                lock.lock();
                if (list.size() != 0) {
                   list.remove(0);
                }                      
                lock.unlock();
            }
        }
    
        static class Producer extends Thread {
            private List<String> list;
            private Lock lock;
            public Producer(List<String> list, Lock lock) {
                this.list = list;
                this.lock = lock;
            }
            @Override
            public void run() {
                    lock.lock();
                    list.add("hello");                    
                    lock.unlock();
            }
        }

These strings are calling IllegalMonitorStateException.

Upvotes: 1

Stephen C
Stephen C

Reputation: 718708

line lock.wait throws IllegalMonitorStateException. Why?

Actually, there is no such line.

However, there is a line that calls list.wait(). And that is the cause of your problems.

In order to call wait() on an object, you must first be holding the primitive mutex lock on that object. You can only get that kind of lock using synchronized. (Either a synchronized method or a synchronized block.)

In your case:

  • You are calling wait on the List instance.
  • You are locking the Lock instance.
  • You are holding the wrong kind of lock for Object.wait. You are holding a Lock lock, not holding a primitive mutex lock.

So ... if you want to do the equivalent of wait and notify on a Lock instance, then when you need to do is to call Lock.newCondition() to get a Condition object. Then you use it like this:

private final Lock lock = ...
private final Condition cond = lock.newCondition();

try {
    lock.acquire();
    while (!the_condition_we_are_waiting_for) {
        cond.await();
    }
    // do stuff
} finally {
   lock.release();
}

For reference, the above would look like this if you rewrote it to use a primitive mutex.

private final Object lock = new Object();

synchronized(lock) {
    while (!the_condition_we_are_waiting_for) {
        lock.wait();
    }
    // do stuff
}

(You could use any object as the lock, but it is a good idea to use an object that is hidden, and won't be locked by any other code.)


In summary, either use a primitive mutex with synchronized, Object.wait and Object.notify* OR use a Lock with Lock.acquire, Lock.release, Condition.await and Condition.signal. Don't try to mix the two kinds of locking and condition variables.

Upvotes: 0

Related Questions