java多线程notify()无法唤醒wait()问题

创建两个Runnable,其中一个的run()方法启动并调用wait(),第二个Runnable中run()方法在一定的几秒之后,为第一个任务调用notify(),从而使得第一个Runnable能显示一条信息,用Executor来测试。

public class RunnableWait implements Runnable{

    public Object obj=new Object();
    @Override
    public void run() {
        synchronized (obj) 
        {
                System.out.println(Thread.currentThread()+"开始等待"+obj);
                try 
                {
                    obj.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread()+"等待结束!"+obj);
            }
    }
    public Object getLock()
    {
        return obj;
    }
}
import java.util.concurrent.TimeUnit;
public class RunnableNotify implements Runnable{

    private RunnableWait rwait=new RunnableWait();
    private Object obj=rwait.getLock();
    @Override
    public void run() 
    {
        synchronized (obj)
        {
            try 
            {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread()+"唤醒rwait!"+obj);
            obj.notifyAll();
            System.out.println(Thread.currentThread()+"唤醒结束!"+obj);
        }
    }
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorMain {

    public static void main(String[] args) {
    ExecutorService exe =Executors.newCachedThreadPool();
        exe.execute(new RunnableWait());
        exe.execute(new RunnableNotify());
        exe.shutdown();
    }
}

会发现RunnableWait的wait()无法被唤醒。
原因:在RunnableNotify中由rwait.getLock()获得的Object对象已经与在ExecutorMain 类执行的exe.execute(new RunnableWait())的RunnableWait对象中产生的Object对象不同。换言之,RunnableNotify中的同步对象锁obj与RunnableWait中的对象锁不为同一个对象。所以也就导致的在RunnableNotify中的run()中的同步代码块中obj.notify()无法唤醒RunnableWait中的obj.wait()。
验证:把RunnableNotify中

System.out.println(Thread.currentThread()+"唤醒rwait!"+obj);

变成

System.out.println(Thread.currentThread()+"唤醒rwait!"+obj+"/"+rwait.getLock());

结果:
可以看出RunnableWait中obj与RunnableNotify中obj不同
解决方法
①:把RunnableWait中的obj设置为public static,删除getLock()方法,在RunnableNotify中直接由类获取RunnableWait中的obj。
代码:

public class RunnableWait implements Runnable{

    public static Object obj=new Object();
    @Override
    public void run() {
        synchronized (obj) 
        {
                System.out.println(Thread.currentThread()+"开始等待"+obj);
                try 
                {
                    obj.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread()+"等待结束!"+obj);
            }
    }
}
import java.util.concurrent.TimeUnit;

public class RunnableNotify implements Runnable{
    private Object obj=RunnableWait.obj;
    @Override
    public void run() 
    {
        synchronized (obj)
        {
            try 
            {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread()+"唤醒rwait!"+obj);
            obj.notifyAll();
            System.out.println(Thread.currentThread()+"唤醒结束!"+obj);
        }
    }
}

ExecutorMain类不变。
②在创建RunnableWait类时构造函数定义为

public RunnableWait(Object obj)
{
    this.obj=obj;
}

RunnableNotify也如此,

public RunnableNotify(Object obj)
{
    this.obj=obj;
}

在ExecutorMain中创建obj对象引用,执行时:

exe.execute(new RunnableWait(obj));
exe.execute(new RunnableNotify(obj));

③在RunnableNotify的构造方法中获取RunnableWait的对象引用

猜你喜欢

转载自blog.csdn.net/xssl_csdn/article/details/78822868