java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)

Posted 甜菜波波

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)相关的知识,希望对你有一定的参考价值。

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代码  技术分享图片
  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代码  技术分享图片
  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代码  技术分享图片
  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代码  技术分享图片
    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 

转自 https://blog.csdn.net/azhegps/article/details/63031562

以上是关于java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)的主要内容,如果未能解决你的问题,请参考以下文章

wait和notify简单学习

java多线程wait notify join

[多线程]wait和notify

Java线程间通信之wait/notify

Java多线程基础之wait,notify

java同步中,为啥要wait,又notify谁?