一:直接看源码
粉圈中就是出现IllegalMonitorStateException的情况:如果当前线程不是这个对象的监视器的所有者(就是当前对象的锁),就会抛出异常
二:分析
1.不是监视器的所有者:
线程要获得锁之后才能调用这三个方法,这三个方法调用的前提条件就是要满足调用的地方是在同步的代码块或同步方法中,并且是严格在同步代码块或同步方法中!!!
//本段代码中a的同步代码块中调用了b中的f1方法,b调用了c的f2方法,并且在f2中执行了
//这三个方法
public class test
{
public static void main(String[] args)
{
A a = new A();
a.start();
}
}
class A extends Thread{
C c=new C();
public void run()
{
synchronized (this){
c.f1();
}
}
}
class C{
P p=new P();
public void f1(){
p.f2();
}
}
class P{
public void f2(){
notifyAll();
notify();
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
严格的含义:执行的地方是要在同步代码块或者同步方法中,例如上面代码,执行的时候会抛出
IllegalMonitorStateException,就是因为在执行的地方不是在同步代码块或者同步方法中。
将执行的地方改成同步:
public class test
{
public static void main(String[] args)
{
A a = new A();
a.start();
}
}
class A extends Thread{
C c=new C();
public void run()
{
synchronized (this){
c.f1();
}
}
}
class C{
P p=new P();
public void f1(){
p.f2();
}
}
class P{
public void f2(){
synchronized (this){//这里改成了同步
notifyAll();
notify();
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
执行就不会发生任何问题!!
2.the owner of the object's monitor:当前对象的监视器的所有者:
要注意是当前!!!!!!!!!!!!!!!!!!!(这么多个感叹号感受到了吗)
使用同步代码块的时候我们可以指定锁放在哪一个对象上,如以下操作:
package _00000000000123;
public class test
{
public static void main(String[] args)
{
Thread thread = new Thread(new A());
thread.start();
}
}
class A implements Runnable{
B b=new B();
public void run()
{
b.f1();
}
}
class B{
C c=new C();
public void f1(){
c.f2();
}
}
class C{
Object ob1=new Object();
public void f2(){
synchronized (ob1){//将锁放在了ob1这个对象上
notify();
notifyAll();
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
由于:
当前的对象是C的实例对象,ob1是C的实例对象的一个属性,将锁放在了ob1上,那么进入这个同步代码块获得的是ob1这个对象的锁,而并不是当前对象:C的实例对象的锁,就是说不满足当前线程应满足的是当前对象的锁的持有者,所以会抛出IllegalMonitorStateException!!!
将ob1位置改成this,把锁放在当前对象上,就不会发生错误!!
三:总结:
1.要严格的在同步语句中
2.要严格的是当前对象的监视器的所有者!!
不是严格的在同步语句中
不是严格的当前对象的监视器所有者
咳咳:基本会遇到的问题就是这样,语重心长,研究了两天,佬不给本蒟蒻来个一键三连^-^.
四:补充:
唤醒是与锁相关联的:
解读:Monitor就是监视器,也就是锁,这个锁存放的位置是在对象实例的某个地方,也就是与对象是绑定在一起的,当某个对象使用了wait()之后,会进入到WaitSet中,变成了等待的状态,调用notify和notifyAll是从WaitSet中去唤醒的,也就是说:如果两个线程不在同一个监视器中,就无法相互唤醒!!!
当某个线程拿到锁之后,就是Owner,其他尝试去拿锁但没有拿到的就进入了EntryList中,变成了Blocked状态,唤醒是从WaitSet中唤醒,并且将其加入到EntryList中,让其进行锁的争抢。