zoukankan      html  css  js  c++  java
  • Java多线程:wait()和notify()方法详解

    通过前面的内容我们知道,当一个线程正在执行某个对象中被synchronized关键字修饰的方法时,这个对象锁上,其他线程必须等到当前线程执行完后才能访问。

    这个整个过程可以用下图来表示

    一个正在运行的线程想要执行synchronized方法,必须要获得当前对象的锁,如果没有获得则当前对象的锁则会被阻塞在对象锁池当中,直到前一个线程释放了该对象锁,当前线程重新获取到对象锁时,线程恢复到可运行状态,当cpu给它资源时,线程将处于运行状态。

    有上图可见,对于多个线程执行一个synchronized方法,我必须在当前线程执行完后,后面的线程才有机会访问该方法。那如果我就是想在前一个线程执行方法过程中停下来,转而让当前线程执行该方法时,该怎么办?

    这个时候我们就需要使用 wait() 和 notify() 方法了。

    在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。

    Object类中关于等待/唤醒的API详细信息如下:
    notify()        -- 唤醒在此对象监视器上等待的单个线程。
    notifyAll()    -- 唤醒在此对象监视器上等待的所有线程。
    wait()                     -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
    wait(long timeout)     -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。如果 timeout 为零,则不考虑实际时间,在获得通知前该线程将一直等待。
    wait(long timeout, int nanos)  -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。

    所以上面的整个流程描述如下:

    如果当前线程正执行某个synchronized方法时,在synchronized方法内遇到了wait()方法,这时当前线程将阻塞在对象等待池中同时释放掉该对象锁,在对象锁池中等待的线程将争取获得此锁,获得锁的线程将回到Runnable状态。当某个线程调用notify()或者notifyAll方法时()在等待池中的线程将被唤醒,进入到锁池中等待获取锁。(线程调用了notify()或notifyAll()方法时并不会释放锁,并不能让处于wait中的线程立刻执行,只是将其唤醒进入锁池等待获取锁)

    先调用notify()方法,然后在调用wait()方法。这时从notify()到wait()方法之间的这一段代码仍会执行,原因就是:虽然调用notify(),但另外的线程没有获得锁,它还在对象锁池中待着,直到当前线程执行wait()方法释放当前锁才会执行它的方法。

    wait与notify方法都是定义在Object类中,而且是final的,因此会被所有的Java类所继承并且无法重写。这两个方法要求在调用时线程应该已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或块当中。当线程执行了wait方法时,它会释放掉对象的锁。
    另一个会导致线程暂停的方法就是Thread类的sleep方法,它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。

    看一个例子

     1 public class Sample
     2 {
     3     private int number;
     4 
     5     public synchronized void increase()
     6     {
     7         while (0 != number)
     8         {
     9             try
    10             {
    11                 wait();
    12             }
    13             catch (InterruptedException e)
    14             {
    15                 e.printStackTrace();
    16             }
    17         }
    18 
    19         number++;
    20 
    21         System.out.println(number);
    22 
    23         notify();
    24     }
    25 
    26     public synchronized void decrease()
    27     {
    28         while (0 == number)
    29         {
    30             try
    31             {
    32                 wait();
    33             }
    34             catch (InterruptedException e)
    35             {
    36                 e.printStackTrace();
    37             }
    38         }
    39 
    40         number--;
    41 
    42         System.out.println(number);
    43 
    44         notify();
    45     }
    46 }
     1 public class MainTest
     2 {
     3     public static void main(String[] args)
     4     {
     5         Sample sample = new Sample();
     6         
     7         Thread t1 = new IncreaseThread(sample);
     8         Thread t2 = new DecreaseThread(sample);
     9         
    10         Thread t3 = new IncreaseThread(sample);
    11         Thread t4 = new DecreaseThread(sample);
    12         
    13         t1.start();
    14         t2.start();
    15         t3.start();
    16         t4.start();
    17     }
    18 }

    打印结果为0/1交替出现。

  • 相关阅读:
    查看邵杨的源码
    java 读写excle
    绘图的引擎
    handler的使用
    小结
    周末,啦啦啦
    监控宝发布移动应用监控服务 引领移动APM
    监控宝优化升级 创新驱动用户体验
    云智慧:顺势而为 做世界级APM服务商
    性能为王:云智慧APM助小米IT服务能力提升
  • 原文地址:https://www.cnblogs.com/2015110615L/p/6733812.html
Copyright © 2011-2022 走看看