wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放),调用wait方法的一个或多个线程就会解除wait状态,重新参与竞争对象锁,程序如果可以再次得到锁,就可以继续向下运行。

 

  1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。

 

 2)当前线程必须拥有此对象的monitor(即锁),才能调用某个对象的wait()方法能让当前线程阻塞,

    (这种阻塞是通过提前释放synchronized锁,重新去请求锁导致的阻塞,这种请求必须有其他线程通过notify()或者notifyAll()唤醒重新竞争获得锁)

 

 3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;

 (notify()或者notifyAll()方法并不是真正释放锁,必须等到synchronized方法或者语法块执行完才真正释放锁)

 

 4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程,唤醒的线程获得锁的概率是随机的,取决于cpu调度

 

  例子1(错误使用导致线程阻塞):三个线程,线程3先拥有sum对象的锁,然后通过sum.notify()方法通知等待sum锁的线程去获得锁,但是这个时候线程1,2并没有处于wait()导致的阻塞状态,而是在synchronized方法块处阻塞了,所以,这次notify()根本没有通知到线程1,2。然后线程3正常结束,释放掉sum锁,这个时候,线程1就立刻获得了sum对象的锁(通过synchronized获得),然后调用sum.wait()方法释放掉sum的锁,线程2随后获得了sum对象的线程锁(通过synchronized获得),这个时候线程1,2都处于阻塞状态,但是悲催的是,这之后再也没有线程主动调用sum.notify()或者notifyAll()方法显示唤醒这两个线程,所以程序阻塞

Java代码  java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)_java
  1. public class CyclicBarrierTest {  
  2.       
  3.     public static void main(String[] args) throws Exception {  
  4.         final Sum sum=new Sum();  
  5.           
  6.         new Thread(new Runnable() {  
  7.             @Override  
  8.             public void  run() {  
  9.                 try {  
  10.                     synchronized (sum) {  
  11.                         System.out.println("thread3 get lock");  
  12.                         sum.sum();  
  13.                         sum.notifyAll(); //此时唤醒没有作用,没有线程等待  
  14.                         Thread.sleep(2000);  
  15.                         System.out.println("thread3 really release lock");  
  16.                     }  
  17.                       
  18.                 } catch (Exception e) {  
  19.                     e.printStackTrace();  
  20.                 }  
  21.             }  
  22.         }).start();  
  23.           
  24.         new Thread(new Runnable() {  
  25.             @Override  
  26.             public void  run() {  
  27.                 try {  
  28.                     synchronized (sum) {  
  29.                         System.out.println("thread1 get lock");  
  30.                         sum.wait();//主动释放掉sum对象锁  
  31.                         System.out.println(sum.total);  
  32.                         System.out.println("thread1 release lock");  
  33.                     }  
  34.                 } catch (Exception e) {  
  35.                     e.printStackTrace();  
  36.                 }  
  37.             }  
  38.         }).start();  
  39.           
  40.         new Thread(new Runnable() {  
  41.             @Override  
  42.             public void  run() {  
  43.                 try {  
  44.                     synchronized (sum) {  
  45.                         System.out.println("thread2 get lock");  
  46.                         sum.wait();  //释放sum的对象锁,等待其他对象唤醒(其他对象释放sum锁)  
  47.                         System.out.println(sum.total);  
  48.                         System.out.println("thread2 release lock");  
  49.                     }  
  50.                 } catch (Exception e) {  
  51.                     e.printStackTrace();  
  52.                 }  
  53.             }  
  54.         }).start();  
  55.     }  
  56.             
  57. }  
  58.   
  59. class Sum{  
  60.     public Integer total=0;  
  61.       
  62.     public void  sum() throws Exception{  
  63.         total=100;  
  64.         Thread.sleep(5000);  
  65.     }  
  66.       
  67. }  

 

 

    运行结果:

 

Java代码  java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)_java
  1. thread3 get lock  
  2. thread3 really release lock  
  3. thread2 get lock  
  4. thread1 get lock  
  5. //程序后面一直阻塞  

 例子2:还是上面程序,顺序不同,把线程3放到最下面。最后线程1,2都因为没有再次获得线程导致线程阻塞

 

运行过程:

线程1先运行获得sum对象锁(通过synchronized),但是随后执行了sum.wait()方法,主动释放掉了sum对象锁,然后线程2获得了sum对象锁(通过synchronized),也通过sum.wait()失去sum的对象锁,最后线程3获得了sum对象锁(通过synchronized),主动通过sum.notify()通知了线程1或者2,假设是1,线程1重新通过notify()/notifyAll()的方式获得了锁,然后执行完毕,随后线程释放锁,然后这个时候线程2成功获得锁,执行完毕。

Java代码  java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)_java
  1. public class CyclicBarrierTest {  
  2.       
  3.     public static void main(String[] args) throws Exception {  
  4.         final Sum sum=new Sum();  
  5.           
  6.       
  7.           
  8.         new Thread(new Runnable() {  
  9.             @Override  
  10.             public void  run() {  
  11.                 try {  
  12.                     synchronized (sum) {  
  13.                         System.out.println("thread1 get lock");  
  14.                         sum.wait();//主动释放sum对象锁,等待唤醒  
  15.                         System.out.println(sum.total);  
  16.                         System.out.println("thread1 release lock");  
  17.                     }  
  18.                 } catch (Exception e) {  
  19.                     e.printStackTrace();  
  20.                 }  
  21.             }  
  22.         }).start();  
  23.           
  24.         new Thread(new Runnable() {  
  25.             @Override  
  26.             public void  run() {  
  27.                 try {  
  28.                     synchronized (sum) {  
  29.                         System.out.println("thread2 get lock");  
  30.                         sum.wait();  //主动释放sum对象锁,等待唤醒  
  31.                         System.out.println(sum.total);  
  32.                         System.out.println("thread2 release lock");  
  33.                     }  
  34.                 } catch (Exception e) {  
  35.                     e.printStackTrace();  
  36.                 }  
  37.             }  
  38.         }).start();  
  39.           
  40.         new Thread(new Runnable() {  
  41.             @Override  
  42.             public void  run() {  
  43.                 try {  
  44.                     synchronized (sum) {  
  45.                         System.out.println("thread3 get lock");  
  46.                         sum.sum();  
  47.                         sum.notifyAll();//唤醒其他等待线程(线程1,2)  
  48.                         Thread.sleep(2000);  
  49.                         System.out.println("thread3 really release lock");  
  50.                     }  
  51.                       
  52.                 } catch (Exception e) {  
  53.                     e.printStackTrace();  
  54.                 }  
  55.             }  
  56.         }).start();  
  57.           
  58.           
  59.     }  
  60.             
  61. }  
  62.   
  63. class Sum{  
  64.     public Integer total=0;  
  65.       
  66.     public void  sum() throws Exception{  
  67.         total=100;  
  68.         Thread.sleep(5000);  
  69.     }  
  70.       
  71. }  

 

执行结果:

Java代码  java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)_java
    1. thread1 get lock  
    2. thread2 get lock  
    3. thread3 get lock  
    4. thread3 really release lock  
    5. 100  
    6. thread2 release lock  
    7. 100  
    8. thread1 release lock