Object对象的wait、notify和notifyAll使用方法

Object对象的wait、notify和notifyAll使用方法

Object的wait、notify 和 notifyAll是Object提供的同步方法,也就是所有对象都生而带来的方法,估计搞java的没有不知道这几个方法的。那么他究竟是怎么使用的呢?

一.先说答案,再进行讲解

  • wait() 与 notify()/notifyAll() 是Object类的方法,在执行两个方法时,要先获得锁。
  • 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。
  • 当执行 notify()/notifyAll() 方法时,会唤醒一个处于等待该 对象锁 的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁。

注意:
从这里可以看出,notify()/notifyAll()执行后,并不立即释放锁,而是要等到执行完临界区中代码后,再释放。所以在实际编程中,我们应该尽量在线程调用 notify()/notifyAll() 后,立即退出临界区。即不要在 notify()/notifyAll() 后面再写一些耗时的代码。

二.正确示例

public class SynchronizedTest {
    public static void main(String[] args) throws Exception {
        Thread mt = new Thread(){
            @Override
            public void run() {
                synchronized (this) {
                    System.out.println("开始阻塞啦");
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("阻塞结束啦");
                }
            }
        };
        mt.start();
        Thread.sleep(500);
        synchronized (mt) {
            mt.notify();
        }
    }
}

运行结果:

开始阻塞啦
阻塞结束啦

上面的例子中,wait和notify方法都是在synchronized代码体中执行的,如果没有经过synchronized修饰,直接使用则会抛出java.lang.IllegalMonitorStateException异常。
至于原因,jdk源码wait方法中的描述为:

* The current thread must own this object's monitor. The thread
* releases ownership of this monitor and waits until another thread
* notifies threads waiting on this object's monitor to wake up
* either through a call to the {@code notify} method or the
* {@code notifyAll} method. The thread then waits until it can
* re-obtain ownership of the monitor and resumes execution.

翻译过来:

当前线程必须拥有此对象监视器。该线程释放对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。

总结过来就是:要想使用wait等一系列方法,必须拥有当前对象的监视器(很多地方称为监视器锁)。

使用 synchronized 关键字,可以获取对象的监视器,对对象加锁

三.错误示例1

public class SynchronizedTest {
    public static void main(String[] args) throws Exception {
        Thread mt = new Thread(){
            @Override
            public void run() {
                synchronized (this) {
                    System.out.println("开始阻塞啦");
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("阻塞结束啦");
                }
            }
        };
        mt.start();
        Thread.sleep(500);
//        synchronized (mt) {
            mt.notify();
//        }
    }
}

执行结果:

开始阻塞啦
Exception in thread "main" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at xxx

原因:

notify方法没有获得监视器。

四.错误示例2

public class SynchronizedTest {
    public static void main(String[] args) throws Exception {
        Thread mt = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    System.out.println("开始阻塞啦");
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("阻塞结束啦");
                }
            }
        });
        mt.start();
        Thread.sleep(500);
        synchronized (mt) {
            mt.notify();
        }
    }
}

执行结果:

开始阻塞啦
(线程持续wait中。。。

原因:

这个例子网上某个人写的错误写法,并不是wait和notify错误使用导致的问题,而是错误使用Runnable导致的,防止有人也会一时想不明白,也贴出来。

例子中使用 new Runnable 创建了一个匿名内部类并作为构造参数传给new Thread,导致构造的对象mt和匿名内部类的this不是同一个对象。所以导致notify不起作用= =、

引用:
1.https://www.cnblogs.com/dreamowneryong/p/11607742.html

猜你喜欢

转载自blog.csdn.net/godloveleo9527/article/details/109207975
今日推荐