wait、notify、notifyAll 的用法

wait()、notify()、notifyAll()是三个定义在Object类里的方法,用来控制线程的状态,通常与synchronized合用。这三个方法最终调用的都是jvm的native方法, 随着jvm运行平台的不一样可能有些许差别。java

当线程执行wait()方法时候,会释放当前对象的控制权,而后让出CPU,进入等待状态;
只有当 notify/notifyAll() 被执行时候,才会唤醒一个或多个正处于等待状态的线程(并不会马上释放控制权),而后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,再次释放锁
多线程


wait() 须要被try catch包围,抛出InterruptedException; 中断也可使wait等待的线程唤醒。
notify方法只唤醒一个等待对象的线程并使该线程开始执行。因此若是有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪一个线程取决于操做系统对多线程管理的实现。
notifyAll 会唤醒全部等待对象的线程,哪个线程将会第一个处理取决于操做系统的实现。jvm

要注意的是:spa

  1. 任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。
  2. 不管是执行对象的wait、notify仍是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)
  3. 若是在没有控制权的线程里执行对象的以上三种方法,报java.lang.IllegalMonitorStateException异常。
  4. JVM基于多线程,默认状况下不能保证运行时线程的时序性

eg.1操作系统

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SyncTest {
    public static void main(String[] args) {
        Object obj = new Object();
        Thread thread1 = new Thread(() -> {
            synchronized (obj) {
                try {
                    log.info("1-before wait");
                    obj.wait();
                    log.info("1-after wait");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        });

        Thread thread2 = new Thread(() -> {
            synchronized (obj) {
                try {
                    log.info("2-before wait");
                    obj.wait();
                    log.info("2-after wait");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        });
        Thread thread3 = new Thread(() -> {
            synchronized (obj) {
                try {
                    log.info("3-before notifyAll");
                    obj.notifyAll();
                    try {
                        Thread.currentThread().sleep(2000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    log.info("3-after notifyAll");

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.currentThread().sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            log.info("3-out synchronized");

        });

        thread1.start();
        thread2.start();

        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        thread3.start();

    }
}

结果: 线程3在sleep前,已经notifyall。但在sleep的时间中,线程1和线程2并无继续执行。.net

2018-10-23 16:15:22,897 [Thread-1] INFO   [SyncTest] [SyncTest.java:24]   2-before wait
2018-10-23 16:15:22,906 [Thread-0] INFO   [SyncTest] [SyncTest.java:11]   1-before wait
2018-10-23 16:15:23,896 [Thread-2] INFO   [SyncTest] [SyncTest.java:43]   3-before notifyAll
2018-10-23 16:15:25,896 [Thread-2] INFO   [SyncTest] [SyncTest.java:50]   3-after notifyAll
2018-10-23 16:15:25,898 [Thread-0] INFO   [SyncTest] [SyncTest.java:13]   1-after wait
2018-10-23 16:15:25,898 [Thread-1] INFO   [SyncTest] [SyncTest.java:26]   2-after wait
2018-10-23 16:15:27,897 [Thread-2] INFO   [SyncTest] [SyncTest.java:61]   3-out synchronized

验证:拥有控制权的线程notify在结束执行synchronized块以前时,控制权不会释放!线程

eg.2code

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SyncTest {
    public static void main(String[] args) {
        Object obj = new Object();
        Thread thread1 = new Thread(() -> {
            synchronized (obj) {
                try {
                    log.info("1-before wait");
                    obj.wait();
                    log.info("1-after wait");
                } catch (Exception e) {
                    log.info("1-catch {}. interrupt状态: {}", e.toString(), Thread.currentThread().isInterrupted());
                    Thread.currentThread().interrupt();
                    log.info("设置标志位后interrupt状态: {}", Thread.currentThread().isInterrupted());

                }
            }
        });

        thread1.start();
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        log.info("线程初始interrupt状态:{}", thread1.isInterrupted());
        thread1.interrupt();

    }
}

结果: 当线程调用interrupt()时,wait()抛出的InterruptedException被线程捕获。对象

2018-10-23 17:13:38,047 [Thread-0] INFO   [SyncTest] [SyncTest.java:10]   1-before wait
2018-10-23 17:13:40,042 [main] INFO   [SyncTest] [SyncTest.java:28]   线程初始interrupt状态:false
2018-10-23 17:13:40,044 [Thread-0] INFO   [SyncTest] [SyncTest.java:14]   1-catch java.lang.InterruptedException. interrupt状态: false
2018-10-23 17:13:40,044 [Thread-0] INFO   [SyncTest] [SyncTest.java:16]   设置标志位后interrupt状态: true

验证:Thread.currentThread().interrupt() 与 thread1.interrupt() 做用类似, 将中断标记位设置为true。 抛出的异常被捕获后,中断标示会被清除!blog

 

wait与notifyAll实现简单的生产者与消费者

相关文章
相关标签/搜索