Reputation: 444
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
Reputation: 2860
You have some problems with your code, namely:
list.wait();
you can't acquire the list's monitor unless you are within a synchronized method (or block code).
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
Reputation: 718708
line
lock.wait
throwsIllegalMonitorStateException
. 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:
wait
on the List
instance.Lock
instance.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