wait()和notify()和notifyAll()

转载:https://www.cnblogs.com/xrq730/p/4853932.html

wait/notify   wait释放锁/notify不释放锁

在Object对象中有三个方法wait()、notify()、notifyAll(),既然是Object中的方法,那每个对象自然都是有的。如果不接触多线程的话,这两个方法是不太常见的。下面看一下前两个方法:

1、wait()

wait()的作用是使当前执行代码的线程进行等待,将当前线程置入"预执行队列"中,并且wait()所在的代码处停止执行,直到接到通知或被中断。在调用wait()之前,线程必须获得该对象的锁,因此只能在同步方法/同步代码块中调用wait()方法

2、notify()

notify()的作用是,如果有多个线程等待,那么线程规划器随机挑选出一个wait的线程,对其发出通知notify(),并使它等待获取该对象的对象锁。注意"等待获取该对象的对象锁",这意味着,即使收到了通知,wait的线程也不会马上获取对象锁,必须等待notify()方法的线程释放锁才可以。和wait()一样,notify()也要在同步方法/同步代码块中调用

总结起来就是,wait()使线程停止运行,notify()使停止运行的线程继续运行

wait()/notify()使用示例

看一段代码:

复制代码

public class MyThread30_0 extends Thread
{
    private Object lock;
    
    public MyThread30_0(Object lock)
    {
        this.lock = lock;
    }
    
    public void run()
    {
        try
        {
            synchronized (lock)
            {
                System.out.println("开始------wait time = " + System.currentTimeMillis());
                lock.wait();
                System.out.println("结束------wait time = " + System.currentTimeMillis());
            }
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

复制代码

复制代码

public class MyThread30_1 extends Thread
{
    private Object lock;
    
    public MyThread30_1(Object lock)
    {
        this.lock = lock;
    }
    
    public void run()
    {
        synchronized (lock)
        {
            System.out.println("开始------notify time = " + System.currentTimeMillis());
            lock.notify();
            System.out.println("结束------notify time = " + System.currentTimeMillis());
        }
    }
}

复制代码

写个main函数,同样的Thread.sleep(3000)也是为了保证mt0先运行,这样才能看到wait()和notify()的效果:

复制代码

public static void main(String[] args) throws Exception
{
    Object lock = new Object();
    MyThread30_0 mt0 = new MyThread30_0(lock);
    mt0.start();
    Thread.sleep(3000);
    MyThread30_1 mt1 = new MyThread30_1(lock);
    mt1.start();
}

复制代码

看一下运行结果:

开始------wait time = 1443931599021
开始------notify time = 1443931602024
结束------notify time = 1443931602024
结束------wait time = 1443931602024

第一行和第二行之间的time减一下很明显就是3s,说明wait()之后代码一直暂停,notify()之后代码才开始运行。

wait()方法可以使调用该线程的方法释放共享资源的锁,然后从运行状态退出,进入等待队列,直到再次被唤醒。

notify()方法可以随机唤醒等待队列中等待同一共享资源的一个线程,并使得该线程退出等待状态,进入可运行状态

notifyAll()方法可以使所有正在等待队列中等待同一共享资源的全部线程从等待状态退出,进入可运行状态 

最后,如果wait()方法和notify()/notifyAll()方法不在同步方法/同步代码块中被调用,那么虚拟机会抛出java.lang.IllegalMonitorStateException,注意一下。

wait()释放锁以及notify()不释放锁

多线程的学习中,任何地方都要关注"锁",wait()和notify()也是这样。wait()方法是释放锁的,写一个例子来证明一下:

复制代码

public class ThreadDomain31
{
    public void testMethod(Object lock)
    {
        try
        {
            synchronized (lock)
            {
                System.out.println(Thread.currentThread().getName() + " Begin wait()");
                lock.wait();
                System.out.println(Thread.currentThread().getName() + " End wait");
            }
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

复制代码

复制代码

public class MyThread31 extends Thread
{
    private Object lock;
    
    public MyThread31(Object lock)
    {
        this.lock = lock;
    }
    
    public void run()
    {
        ThreadDomain31 td = new ThreadDomain31();
        td.testMethod(lock);
    }
}

复制代码

main函数调用一下:

复制代码

public static void main(String[] args)
{
    Object lock = new Object();
    MyThread31 mt0 = new MyThread31(lock);
    MyThread31 mt1 = new MyThread31(lock);
    mt0.start();
    mt1.start();
}

复制代码

看一下运行结果:

Thread-0 Begin wait()
Thread-1 Begin wait()

如果wait()方法不释放锁,那么Thread-1根本不会进入同步代码块打印的,所以,证明完毕。

接下来证明一下notify()方法不释放锁的结论:

复制代码

public class ThreadDomain32
{
    public void testMethod(Object lock)
    {
        try
        {
            synchronized (lock)
            {
                System.out.println("Begin wait(), ThreadName = " + Thread.currentThread().getName());
                lock.wait();
                System.out.println("End wait(), ThreadName = " + Thread.currentThread().getName());
            }
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
    
    public void synNotifyMethod(Object lock)
    {
        try
        {
            synchronized (lock)
            {
                System.out.println("Begin notify(), ThreadName = " + Thread.currentThread().getName());
                lock.notify();
                Thread.sleep(5000);
                System.out.println("End notify(), ThreadName = " + Thread.currentThread().getName());
            }
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

复制代码

写两个线程分别调用2个方法:

复制代码

public class MyThread32_0 extends Thread
{
    private Object lock;
    
    public MyThread32_0(Object lock)
    {
        this.lock = lock;
    }
    
    public void run()
    {
        ThreadDomain32 td = new ThreadDomain32();
        td.testMethod(lock);
    }
}

复制代码

复制代码

public class MyThread32_1 extends Thread
{
    private Object lock;
    
    public MyThread32_1(Object lock)
    {
        this.lock = lock;
    }
    
    public void run()
    {
        ThreadDomain32 td = new ThreadDomain32();
        td.synNotifyMethod(lock);
    }
}

复制代码

写个main函数调用一下:

复制代码

public static void main(String[] args) throws Exception
{
    Object lock = new Object();
    MyThread32_0 mt0 = new MyThread32_0(lock);
    mt0.start();
    MyThread32_1 mt1 = new MyThread32_1(lock);
    mt1.start();
    MyThread32_1 mt2 = new MyThread32_1(lock);
    mt2.start();
}

复制代码

看一下运行结果:

Begin wait(), ThreadName = Thread-0
Begin notify(), ThreadName = Thread-1
End notify(), ThreadName = Thread-1
Begin notify(), ThreadName = Thread-2
End notify(), ThreadName = Thread-2
End wait(), ThreadName = Thread-0

如果notify()方法释放锁,那么在Thread-1调用notify()方法后Thread.sleep(5000)必定应该有其他线程可以进入同步代码块了,但是实际上没有,必须等到Thread-1把代码执行完。所以,证明完毕。

猜你喜欢

转载自blog.csdn.net/qq_33366098/article/details/86485306