wait()、notify()、notifyAll()是三个定义在Object类里的方法,用来控制线程的状态,通常与synchronized合用。这三个方法最终调用的都是jvm的native方法, 随着jvm运行平台的不一样可能有些许差别。java
当线程执行wait()方法时候,会释放当前对象的控制权,而后让出CPU,进入等待状态;
只有当 notify/notifyAll() 被执行时候,才会唤醒一个或多个正处于等待状态的线程(并不会马上释放控制权),而后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,再次释放锁。多线程
wait() 须要被try catch包围,抛出InterruptedException; 中断也可使wait等待的线程唤醒。
notify方法只唤醒一个等待对象的线程并使该线程开始执行。因此若是有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪一个线程取决于操做系统对多线程管理的实现。
notifyAll 会唤醒全部等待对象的线程,哪个线程将会第一个处理取决于操做系统的实现。jvm
要注意的是:spa
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