JAVA 并发编程-传统线程同步通信技术(四)
发布日期:2022-01-11 03:09:47 浏览次数:4 分类:技术文章

本文共 2557 字,大约阅读时间需要 8 分钟。

首先介绍几个概念:

 

这些方法都是Object的方法,并不是线程的方法!

wait()方法

 

  wait()方法使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。 

  当前的线程必须拥有当前对象的monitor,也即lock,就是锁。 

  线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法),这样它才能重新获得锁的拥有权和恢复执行。 

  要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。

 

    与sleep比较:

 

     当线程调用了wait()方法时,它会释放掉对象的锁。 

     另一个会导致线程暂停的方法:Thread.sleep(),它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。

 

notify()方法

 

  notify()方法会唤醒一个等待当前对象的锁的线程。

  如果多个线程在等待,它们中的一个将会选择被唤醒。这种选择是随意的,和具体实现有关。(线程等待一个对象的锁是由于调用了wait方法中的一个)。

  被唤醒的线程是不能被执行的,需要等到当前线程放弃这个对象的锁。

  被唤醒的线程将和其他线程以通常的方式进行竞争,来获得对象的锁。也就是说,被唤醒的线程并没有什么优先权,也没有什么劣势,对象的下一个线程还是需要通过一般性的竞争。

  notify()方法应该是被拥有对象的锁的线程所调用。

 

  换句话说,和wait()方法一样,notify方法调用必须放在synchronized方法或synchronized块中。

  wait()和notify()方法要求在调用时线程已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或synchronized块中。

 

线程同步通信实现demo:

 

传统线程同步通信技术,子线程循环10次,接着主线程循环100次,又回到子线程循环10次,接着再回到主线程又循环100次,如此循环50次

[java]
  1. public class TraditionalThreadCommunication {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.           
  8.         final Business business = new Business();  
  9.         //创建了一个线程,并启动  
  10.         new Thread(  
  11.                 new Runnable() {  
  12.                       
  13.                     @Override  
  14.                     public void run() {  
  15.                       
  16.                         for(int i=1;i<=50;i++){  
  17.                             //business的子函数  
  18.                             business.sub(i);  
  19.                         }  
  20.                           
  21.                     }  
  22.                 }  
  23.         ).start();  
  24.         //因为mian方法本身就占用一个线程,所以主线程不需要再new Thread       
  25.         for(int i=1;i<=50;i++){  
  26.             business.main(i);  
  27.         }         
  28.           
  29.     }  
  30.   
  31. }  
  32.   class Business {  
  33.         
  34.       private boolean bShouldSub = true;  
  35.       //互斥对象为business,即在同一时刻只能访问sub或main其中一个方法  
  36.       public synchronized void sub(int i){  
  37.           //当bShouldSub==false时等待  
  38.           while(!bShouldSub){  
  39.               try {  
  40.                 //方法使当前线程主动释放互斥锁,并进入该互斥锁的等待队列。(也就是说,它使当前线程暂停执行,  
  41.                 //等待其他线程执行notify()方法或者notifyall()方法后再继续执行本线程。)  
  42.                 this.wait();  
  43.             } catch (InterruptedException e) {                
  44.                 e.printStackTrace();  
  45.             }  
  46.           }  
  47.           for(int j=1;j<=10;j++){  
  48.                 System.out.println("sub thread sequence of " + j + ",loop of " + i);  
  49.           }  
  50.           bShouldSub = false;  
  51.           //this代表什么?--代表Business  
  52.           //唤醒下一个线程  
  53.           //唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。  
  54.           //选择是任意性的,并在对实现做出决定时发生。  
  55.           this.notify();  
  56.       }  
  57.         
  58.       public synchronized void main(int i){  
  59.             //当bShouldSub==true时等待  
  60.             while(bShouldSub){  
  61.                 try {  
  62.                     this.wait();  
  63.                 } catch (InterruptedException e) {                    
  64.                     e.printStackTrace();  
  65.                 }  
  66.             }  
  67.             for(int j=1;j<=100;j++){  
  68.                 System.out.println("main thread sequence of " + j + ",loop of " + i);  
  69.             }  
  70.             bShouldSub = true;  
  71.             this.notify();  
  72.       }  
  73.   }  

打印结果:

总结:

 

   

    wait()和notify()方法要求在调用时线程已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或synchronized块中。synchronized保证了mainsub两个方法在同一时刻只能有一个在执行,那么bShouldSub值就是在判断该哪个方法执行。

 

    执行过程可能为:sub()方法先执行(当然也可能是main方法先执行,只是bShouldSub==true,则会的wait),bShouldSub==true,执行for循环,之后设置bShouldSub=false,并唤醒等待线程,这时可能还是执行sub()方法(被唤醒的线程并没有什么优先权,也没有什么劣势,对象的下一个线程还是需要通过一般性的竞争),但此时bShouldSub==false,故执行while语句,wait,然后main()方法执行。

转载地址:https://yuki-ho.blog.csdn.net/article/details/52217380 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:JAVA 并发编程-线程范围内共享变量(五)
下一篇:微信 模版消息 (六)

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月18日 22时32分21秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章