`
bcyy
  • 浏览: 1818604 次
文章分类
社区版块
存档分类
最新评论

Java多线程之wait()和notify()

 
阅读更多

直接看测试代码吧,细节之处,详见注释

  1. packagecom.jadyer.thread.wait;
  2. /**
  3. *Java多线程之wait()和notify()的妙用
  4. *@see=================================================================================================================
  5. *@see问题:同时启动两个线程和同时启动四个线程,控制台打印结果是不同的
  6. *@see同时启动两个线程时,控制台会很规律的输出1010101010101010
  7. *@see同时启动四个线程时,控制台起初会规律的输出10101010,一旦某一刻输出一个负数,那么后面的输出就会"一错再错"
  8. *@see分析:对线程而言,任何一种情况,都是合理的
  9. *@see这里假设其中的一种情况:tt22先执行,此时number=0,所以执行到了decrease()方法中的wait()方法,于是tt22被阻塞
  10. *@see接着tt44执行了,此时number=0,所以也执行到了decrease()方法中的wait()方法,于是tt44也被阻塞了
  11. *@see然后tt11执行了,此时number=0,www.linuxidc.com于是便执行到了increase()方法中的number++和notify()方法
  12. *@see重点在于tt11执行到notify()方法时,我们假设该方法唤醒了tt44线程,于是tt44开始执行decrease()方法中的number--
  13. *@see此时number=-1,然后执行到了decrease()方法中notify()方法,我们同样假设该notify()方法唤醒的是tt22线程
  14. *@see同样的道理,number又被减减了,于是number=-2,并被打印到控制台了,然后再假设tt22中的notify()方法唤醒的是tt11
  15. *@see如此的循环往复,就看到那种"一错再错"的效果了
  16. *@see=================================================================================================================
  17. *@see修复:我们应当在wait()被唤醒的时候,再判断一次,然后再决定是否让该线程继续wait()下去
  18. *@see因为,当某个线程被唤醒时,它不知道外界在其睡眠的期间发生了神马,所以要再判断一次。所以把if()改为while()判断,即可
  19. *@see=================================================================================================================
  20. *@see补充:如果只有两个线程的话,一个是对number增加的线程,一个是对number减少的线程,此时用if()判断是没有问题的
  21. *@see因为无论线程如何的唤醒,它所唤醒的都是另一个线程,不存在第三个线程插进来捣乱的情况
  22. *@see=================================================================================================================
  23. *@author宏宇
  24. *@createFeb22,20123:20:05PM
  25. */
  26. publicclassWaitNotifyTest{
  27. publicstaticvoidmain(String[]args){
  28. Countcount=newCount();
  29. Threadtt11=newThread(newIncreaseThread(count));
  30. Threadtt22=newThread(newDecreaseThread(count));
  31. Threadtt33=newThread(newIncreaseThread(count));
  32. Threadtt44=newThread(newDecreaseThread(count));
  33. tt11.start();
  34. tt22.start();
  35. tt33.start();
  36. tt44.start();
  37. }
  38. }
  39. classIncreaseThreadimplementsRunnable{
  40. privateCountcount;
  41. publicIncreaseThread(Countcount){
  42. this.count=count;
  43. }
  44. @Override
  45. publicvoidrun(){
  46. for(inti=0;i<20;i++){
  47. try{
  48. Thread.sleep((long)(Math.random()*1000));
  49. }catch(InterruptedExceptione){
  50. e.printStackTrace();
  51. }
  52. count.increase();
  53. }
  54. }
  55. }
  56. classDecreaseThreadimplementsRunnable{
  57. privateCountcount;
  58. publicDecreaseThread(Countcount){
  59. this.count=count;
  60. }
  61. @Override
  62. publicvoidrun(){
  63. for(inti=0;i<20;i++){
  64. try{
  65. Thread.sleep((long)(Math.random()*1000));
  66. }catch(InterruptedExceptione){
  67. e.printStackTrace();
  68. }
  69. count.decrease();
  70. }
  71. }
  72. }
  73. classCount{
  74. privateintnumber;
  75. publicsynchronizedvoidincrease(){
  76. if(0!=number){
  77. try{
  78. //在同步方法(或者同步语句块)中,被锁定的对象可以调用wait()方法,这将导致当前线程被阻塞并释放该对象的互斥锁
  79. //即解除了wait()方法所对应的当前对象的锁定状态,然后,其它的线程就有机会访问该对象了
  80. wait();
  81. }catch(InterruptedExceptione){
  82. e.printStackTrace();
  83. }
  84. }
  85. number++;
  86. System.out.println(number);
  87. //唤醒其它的由于调用了wait()方法而在等待同一个对象的线程
  88. //该方法每次运行时,只能唤醒等待队列中的一个线程,至于是哪一个线程被唤醒,则由线程调度器来决定,程序员无法控制
  89. notify();
  90. }
  91. publicsynchronizedvoiddecrease(){
  92. if(0==number){
  93. try{
  94. wait();
  95. }catch(InterruptedExceptione){
  96. e.printStackTrace();
  97. }
  98. }
  99. number--;
  100. System.out.println(number);
  101. notify();
  102. }
  103. }
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics