Уведомить, давая IllegalMonitorStateException
У меня очень плохие знания по многопоточности.
Я ожидаю, что нижеприведенная Программа будет работать отлично, но она не работает и выдает ниже Исключения.
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.onmobile.client.D.callD(Deadlock.java:76)
at com.onmobile.client.B.run(Deadlock.java:50)
at java.lang.Thread.run(Unknown Source)
Файл Java
public class Deadlock {
C c = new C();
D d = new D();
public static void main(String[] args) {
new Deadlock();
}
public Deadlock() {
A a = new A(d,c);
B b = new B(d,c);
Thread t1 = new Thread(a);
Thread t2 = new Thread(b);
t1.start();
t2.start();
}
}
class A implements Runnable{
D dObj;
C cObj;
A(D obj, C obj1){
this.dObj = obj;
this.cObj = obj1;
}
@Override
public void run() {
cObj.callC(dObj);
}
}
class B implements Runnable{
D dObj;
C cObj;
B(D obj, C obj1){
this.dObj = obj;
this.cObj = obj1;
}
@Override
public void run() {
dObj.callD(cObj);
}
}
class C{
public synchronized void callC(D dObj){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
dObj.callD1();
}
public synchronized void callC1(){
}
}
class D{
public synchronized void callD(C cObj){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cObj.callC1();
cObj.notify();
}
public synchronized void callD1(){
}
}
Я думал, что внутри метода callC() объект класса C, т.е. cObj переходит в состояние ожидания, а управление переходит в метод callD() и там он вызывает cObj.notify(); Таким образом, это пробудит ожидающие потоки, ожидающие на объекте cObj.
но это дает мне исключение. Я думаю, что решение моей проблемы может быть: Java: IllegalMonitorStateException on notify ()
но я не правильно понимаю
Пожалуйста, ведите меня, где я иду не так.
4 ответа
Если вы хотите уведомить или подождать объекта, ваш поток должен иметь монитор объекта, с которым вы работаете.
public synchronized void callD(C cObj){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cObj.callC1();
cObj.notify();
}
В этом разделе кода вы синхронизируете на экземпляре класса D
Так как синхронизированные методы всегда получают монитор объекта, на котором они "живут". Но чтобы иметь возможность использовать cObj.notify()
Вы должны получить монитор cObj
например, делая
synchronized(cObj) {
cObj.notify();
}
При вызове object.notify вы должны удерживать блокировку для этого точного объекта, то есть:
synchronized(cObj) {
cObj.notify();
}
Вы должны также обернуть свой ожидающий вызов в подобный синхронизированный блок:
synchronized(cObj) {
cObj.wait()
}
Я предлагаю вам прочитать больше об этом в руководстве по Java: http://docs.oracle.com/javase/tutorial/essential/concurrency/
notify
на Object
следует вызывать только после взятия блокировки или synchronizing
на этом объекте. Так что в вашем случае вам нужно:
class D{
public void callD(C cObj){ //synchronized not required here
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronize(cObj) { //synchornize here on cObj
cObj.callC1();
cObj.notify();
}
}
}
Примечание: если вы измените свой код на synchornize callD
а также synchroniz(cObj)
убедитесь, что вы на deadlock
сценарий. Только ИМХО synchroniz(cObj)
должно хватить.
Звонить notify()
на объекте вам нужно владеть замком этого объекта. В этом случае позвонить
cObj.notify();
вам нужно обернуть его в синхронизированный блок следующим образом:
syncronized (cObj)
{
cObj.notify();
}