java多线程初级问题!

/*
多线程之等待唤醒练习
线程运行到wait时 会一直停在那里等待 一直到被唤醒

*/

//实现双线程依次打印show2->show1->show2->show1....
class Demo
{
//标识 实现打印show2-show1-show2...
boolean b;
Demo(boolean b)
{
this.b = b;
}
/*synchronized*/ void show1(int i)
{
// System.out.println(i);
//锁对象定义的是obj1
//个人疑问: 【如果用到wait 定义不同锁对象的效果是否会不按规则打印】
synchronized(myLock.obj1){ //IllegalMonitorStateException 监视器异常?
if(b)
try{wait();}catch(Exception e){} //此代码会将线程T-0处于等待状态 并不会再往下执行
System.out.println("-----------show1---------i="+i+" "+Thread.currentThread().getName());
b = true;
notify();
}
}
/*synchronized*/ void show2(int i)
{

//锁对象定义的是obj2
synchronized(myLock.obj2){
if(!b)
try{wait();}catch(Exception e){}
System.out.println("-----------show2---------i="+i+" "+Thread.currentThread().getName());
b = false;
notify();
}
}
}
class myLock
{
//定义两个锁

public static Object obj1 = new Object();
public static Object obj2 = new Object();
}

class Test1 implements Runnable
{
Demo d;
Test1(Demo d)
{
this.d = d;
}
public void run()
{
for(int i = 1;i<=3;i++)
d.show1(i);
}
}
class Test2 implements Runnable
{
Demo d;
Test2(Demo d)
{
this.d = d;
}
public void run()
{
for(int i = 1;i<=3;i++)
d.show2(i);
}
}
class WaitDemo
{
public static void main(String[] args)
{
Demo d = new Demo(true);
Test1 te1 = new Test1(d);
Test2 te2 = new Test2(d);
Thread t1 = new Thread(te1);
Thread t2 = new Thread(te2);
t1.start();
t2.start();
}
}
为什么我使用不同对象锁时就出了异常 运行异常!!
求大神 谢谢~~
小弟初学者。

3个回答

不知道你用两个锁的目的是什么。如果只是为了协调两个打印的执行顺序,一个锁就可以,并且也是常规做法。
两个锁不是不可以,但完全不适用你的场景。线程的同步控制本来已经很复杂了,你又引入了两个锁,一团乱麻了。
ps:其实你上面出现了三个锁,obj1,obj2,this(你的wait和notify是通过this掉用的) - -!!

有几个建议和概念:
1、锁的抽象概念:锁就像是带锁的一扇门,一个线程进入后就会锁上,门里只有一个线程在运行,其他线程都在门外等候,
直到这个线程执行完了,出去了,这时锁被打开,其他线程中的一个可以进来;或者门里的线程没有执行完,但是放弃了执行,
它会在门里把锁打开(这就是wait),这时其他线程中的一个也可以进入。如果有两个锁,那就是两扇门,凌乱了,根本谈不上控制。

2、锁在代码中就是对象,任何对象都可以作为锁,不同对象就是不同的锁。在同一时间线上,能用一个锁,就用一个锁。

3、wait与notify是锁所拥有的方法,是成对出现的(这里不谈带参数的wait,例如:wait(1000)),并且应该是通过同一个锁调用的。
进入门内的线程会持有锁,它有锁的控制权,在门内,并且只能在门内,才可以通过锁的wait方法,放弃对锁的控制权,这时,
这把锁会通过JVM的线程调度机制分配给某个其他线程,使其他线程有机会进入门内取执行。

        那么如何唤醒处于等待状态的线程呢?
        必须通过notify方法唤醒,但是调用wait的线程已经处于等待状态了,不能自唤醒(因为不是带参数的wait),
        怎么搞,就必须通过别的线程,使用同一把锁调用notify方法来唤醒,如果有多个线程由这个锁而处于等待,notify会选择一个唤醒,
        附带说一下,notifyAll会唤醒所有,但是只有一个被唤醒的才能拥有执行权,其他没有执行权的继续进入等待状态。怕死锁,通常都用notifyAll。

        总结,wait与notify需要通过同一把锁调用,并且,wait是线程让自己处于等待,notify是唤醒其他线程。
        只有门内的线程通过锁才能调用wait与notify,并且只能通过门上的锁进行调用。

你的错误就是因为,你门上的锁是obj1和obj2,但是你调用wait和notify用的却是this,这时jvm会报错。
清楚上面的概念,我想你应该知道该怎么做了。

ps:前面说的使用this是没问题的,this也是对象,可以作为锁,这样你的锁也就是同一个锁:对象this。
当然,如果不用this也是可以的,删除obj2,全部都使用obj1就没问题了。例如:synchronized(myLock.obj1),obj1.wait, obj1.notify。
总之,使用一个锁就没问题了。

测试了你的代码,运行时异常,主要就是因为wait()和notify()方法是Object类的方法,它是内置条件队列,只能跟内置锁一起使用,就是只有持有当前对象的锁时,才能调用这两个方法。即你的synchronized(myLock.obj2)这里只能用synchronized(this),修改后就能正确打印了。(注意两个地方都只能用this锁)。
抛出IllegalMonitorStateException 这个异常是因为"if the current thread is not the owner of this object's monitor."你是两个线程拥有不同的锁导致的。如果要使用者两个方法,必须是获取当前对象的锁即在synchronized(this)代码块中调用wait或者notify才能正确。

建议使用synchronized同步方法,以避免出现运行异常

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问