• 欢迎访问web前端中文站,JavaScript,CSS3,HTML5,web前端demo
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏web前端中文站吧

Java的wait()、 notify()、notifyAll()和线程同步原理

JAVA web前端中文站 4年前 (2017-04-24) 1701次浏览 已收录 0个评论
文章目录[隐藏]

waitnotify是 Java 同步机制中重要的组成部分。结合与 synchronized 关键字使用,可以建立很多优秀的同步模型

使用wait()与notify()/notifyAll()可以使得多个任务之间彼此协作。

wait()与 notify()/notifyAll()

wait(),notify()和notifyAll()都是 java.lang.Object 的方法:

  • wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
  • notify(): Wakes up a single thread that is waiting on this object’s monitor.
  • notifyAll(): Wakes up all threads that are waiting on this object’s monitor.

调用 sleep()和 yield()的时候锁并没有被释放,而调用 wait()将释放锁。这样另一个任务(线程)可以获得当前对象的锁,从而进入它的 synchronized 方法中。可以通过 notify()/notifyAll(),或者时间到期,从 wait()中恢复执行。
只能在同步控制方法或同步块中调用 wait()、notify()和notifyAll()。如果在非同步的方法里调用这些方法,在运行时会抛出 IllegalMonitorStateException 异常。

这三个方法,都是 Java 语言提供的实现线程间阻塞(Blocking)和控制进程内调度(inter-process communication)的底层机制。在解释如何使用前,先说明一下两点:

  1. 正如 Java 内任何对象都能成为锁(Lock)一样,任何对象也都能成为条件队列(Condition queue)。而这个对象里的 wait(), notify()和 notifyAll()则是这个条件队列的固有(intrinsic)的方法。
  2. 一个对象的固有锁和它的固有条件队列是相关的,为了调用对象 X 内条件队列的方法,你必须获得对象 X 的锁。这是因为等待状态条件的机制和保证状态连续性的机制是紧密的结合在一起的。

根据上述两点,在调用 wait(), notify()或 notifyAll()的时候,必须先获得锁,且状态变量须由该锁保护,而固有锁对象与固有条件队列对象又是同一个对象。也就是说,要在某个对象上执行 wait,notify,先必须锁定该对象,而对应的状态变量也是由该对象锁保护的。

再看一下 Java 中 java.lang.Object 类的实现源码:

 public class Object {  
 private static native void registerNatives();  
 static {   registerNatives();    }  
 public final native Class<?> getClass();  
 public native int hashCode();  
 public boolean equals(Object obj) {   
 return (this == obj);  }  
 protected native Object clone() throws CloneNotSupportedException;  
 public String toString() {   
 return getClass().getName() + "@" + Integer.toHexString(hashCode());  }  
 public final native void notify();  
 public final native void notifyAll();  
 public final native void wait(long timeout) throws InterruptedException;  
 public final void wait(long timeout, int nanos) throws InterruptedException {   
 if (timeout < 0) {    
 throw new IllegalArgumentException("timeout value is negative");}   
 if (nanos < 0 || nanos > 999999) {    
 throw new IllegalArgumentException("nanosecond timeout value out of range");}   
 if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {    timeout++;   }         
 wait(timeout);  }  
 public final void wait() throws InterruptedException {         
 wait(0);     }     
 protected void finalize() throws Throwable {} }

wait()方法是 object 类的方法,解决的问题是线程间的同步,该过程包含了同步锁的获取和释放,调用 wait 方法将会将调用者的线程挂起,直到其他线程调用同一个对象的 notify()方法才会重新激活调用者。
注意:线程调用 notify()之后,只有该线程完全从 synchronized 代码里面执行完毕后,monitor 才会被释放,被唤醒线程才可以真正得到执行权。

  • obj.wait()方法使本线程挂起,并释放 obj 对象的 monitor,只有其他线程调用 obj 对象的 notify()或 notifyAll()时,才可以被唤醒。
  • obj.notifyAll()方法唤醒所有阻塞在 obj 对象上的沉睡线程,然后被唤醒的众多线程竞争 obj 对象的 monitor 占有权,最终得到的那个线程会继续执行下去,但其他线程继续等待。
  • obj.notify()方法是随机唤醒一个沉睡线程,过程更 obj.notifyAll()方法类似。

wait,notify 和 notifyAll 只能在同步控制方法或者同步控制块里面使用,例如:

 synchronized(x){  x.notify()   //或者 wait() }

以上内容说明了为什么调用 wait(),notify(),notifyAll()的线程必须要拥有 obj 实例对象的 monitor 占有权。
每个对象实例都有一个等待线程队列。这些线程都是等待对该对象的同步方法的调用许可。对一个线程来说,有两种方法可以进入这个等待线程队列。一个是当其他线程执行同步方法时,自身同时也要执行该同步方法;另一个是调用 obj.wait()方法。
当同步方法执行完毕或者执行 wait()时,其他某个线程将获得对象的访问权。当一个线程被放入等待队列时,必须要确保可以通过 notify()的调用来解冻该线程,以使其能够继续执行下去。

java 线程同步原理

java 会为每个 object 对象分配一个 monitor,当某个对象的同步方法(synchronized methods )或同步快被多个线程调用时,该对象的 monitor 将负责处理这些访问的并发独占要求。
当一个线程调用一个对象的同步方法时,JVM 会检查该对象的 monitor。如果 monitor 没有被占用,那么这个线程就得到了 monitor 的占有权,可以继续执行该对象的同步方法;如果 monitor 被其他线程所占用,那么该线程将被挂起,直到 monitor 被释放。
当线程退出同步方法调用时,该线程会释放 monitor,这将允许其他等待的线程获得 monitor 以使对同步方法的调用执行下去。
注意:java 对象的 monitor 机制和传统的临界检查代码区技术不一样。java 的一个类一个同步方法并不意味着同时只有一个线程独占执行(不同对象的同步方法可以同时执行),但临界检查代码区技术确会保证同步方法在一个时刻只被一个线程独占执行。
java 的 monitor 机制的准确含义是:任何时刻,对一个指定 object 对象的某同步方法只能由一个线程来调用。
java 对象的 monitor 是跟随 object 实例来使用的,而不是跟随程序代码。两个线程可以同时执行相同的同步方法,比如:一个类的同步方法是 xMethod(),有 a,b 两个对象实例,一个线程执行 a.xMethod(),另一个线程执行 b.xMethod(). 互不冲突。


web 前端中文站 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Java 的 wait()、 notify()、notifyAll()和线程同步原理
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址