歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Java多線程之wait()和notify()

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

日期:2017/3/1 10:26:17   编辑:Linux編程

直接看測試代碼吧,細節之處,詳見注釋

  1. package com.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. * @create Feb 22, 2012 3:20:05 PM
  25. */
  26. public class WaitNotifyTest {
  27. public static void main(String[] args) {
  28. Count count = new Count();
  29. Thread tt11 = new Thread(new IncreaseThread(count));
  30. Thread tt22 = new Thread(new DecreaseThread(count));
  31. Thread tt33 = new Thread(new IncreaseThread(count));
  32. Thread tt44 = new Thread(new DecreaseThread(count));
  33. tt11.start();
  34. tt22.start();
  35. tt33.start();
  36. tt44.start();
  37. }
  38. }
  39. class IncreaseThread implements Runnable{
  40. private Count count;
  41. public IncreaseThread(Count count){
  42. this.count = count;
  43. }
  44. @Override
  45. public void run() {
  46. for(int i=0; i<20; i++){
  47. try {
  48. Thread.sleep((long)(Math.random()*1000));
  49. } catch (InterruptedException e) {
  50. e.printStackTrace();
  51. }
  52. count.increase();
  53. }
  54. }
  55. }
  56. class DecreaseThread implements Runnable{
  57. private Count count;
  58. public DecreaseThread(Count count){
  59. this.count = count;
  60. }
  61. @Override
  62. public void run() {
  63. for(int i=0; i<20; i++){
  64. try {
  65. Thread.sleep((long)(Math.random()*1000));
  66. } catch (InterruptedException e) {
  67. e.printStackTrace();
  68. }
  69. count.decrease();
  70. }
  71. }
  72. }
  73. class Count{
  74. private int number;
  75. public synchronized void increase(){
  76. if(0 != number){
  77. try {
  78. //在同步方法(或者同步語句塊)中,被鎖定的對象可以調用wait()方法,這將導致當前線程被阻塞並釋放該對象的互斥鎖
  79. //即解除了wait()方法所對應的當前對象的鎖定狀態,然後,其它的線程就有機會訪問該對象了
  80. wait();
  81. } catch (InterruptedException e) {
  82. e.printStackTrace();
  83. }
  84. }
  85. number++;
  86. System.out.println(number);
  87. //喚醒其它的由於調用了wait()方法而在等待同一個對象的線程
  88. //該方法每次運行時,只能喚醒等待隊列中的一個線程,至於是哪一個線程被喚醒,則由線程調度器來決定,程序員無法控制
  89. notify();
  90. }
  91. public synchronized void decrease(){
  92. if(0 == number){
  93. try {
  94. wait();
  95. } catch (InterruptedException e) {
  96. e.printStackTrace();
  97. }
  98. }
  99. number--;
  100. System.out.println(number);
  101. notify();
  102. }
  103. }
Copyright © Linux教程網 All Rights Reserved