一個關于Java Thread wait(),notify()的實用例(轉)

          一個Java解決生產者-消費者同步問題的例子,很有參考價值的。 

          Java代碼  
          1. /////  
          2. // ProducerConsumer.java  
          3.   
          4. //  
          5. // 這是個很重要的Thread例子。需要注意的是:  
          6. // wait() 必須在synchronized 函數或者代碼塊里面  
          7. // wait()會讓已經獲得synchronized 函數或者代碼塊控制權的Thread暫時休息,并且喪失控制權  
          8. // 這個時候,由于該線程喪失控制權并且進入等待,其他線程就能取得控制權,并且在適當情況下調用notifyAll()來喚醒wait()的線程。  
          9. // 需要注意的是,被喚醒的線程由于已經喪失了控制權,所以需要等待喚醒它的線程結束操作,從而才能重新獲得控制權。  
          10. //  
          11. // 所以wait()的確是馬上讓當前線程喪失控制權,其他的線程可以乘虛而入。  
          12. //  
          13. // 所以wait()的使用,必須存在2個以上線程,而且必須在不同的條件下喚醒wait()中的線程。  
          14. //  
          15. //  
          16. // 以下的例子:  
          17. // ProductStack 是一個生產者跟消費者共享的同步機制,這個機制決定了什么情況生產者要wait(),什么情況消費者要wait()  
          18. // 可以把ProductStack看作一個產品倉庫。當產品倉庫滿的時候,生產者線程需要wait(),從而放棄對產品倉庫的控制。  
          19. // 這個時候消費者線程就可以進來了而取得倉庫的控制權。一旦消費者消費了產品,那么倉庫就不滿了。  
          20. // 這個時候消費者線程就要notifyAll()生產者線程,讓等待的生產者線程喚醒。  
          21. // 但是生產者被喚醒后不能馬上進行生產,因為它在wait()的時候已經喪失了對倉庫的控制權,所以就需要等待消費者線程結束操作,  
          22. // 才能重新取得倉庫的控制權,再進行生產。  
          23. //  
          24. // 所以特別注意的是,notifyAll()并不是讓當前線程馬上讓出控制權,而只是讓其他wait()當中的線程喚醒而已,  
          25. // 所以對不起,盡管我喚醒你,可你必須還是要等我用完倉庫才能進來。這點必須清楚。  
          26. //  
          27. // 相反,倉庫如果空的時候,消費者線程就會wait(),然后等待生產者線程來生產產品,生產者進程乘虛而入后,讓生產者線程生產產品  
          28. // 并且喚醒消費者線程。這個情況跟上面就類似了。  
          29. //  
          30. ///  
          31.   
          32. public class ProducerConsumer {  
          33.   
          34.       public static void main(String[] args) {  
          35.   
          36.            ProductStack ps = new ProductStack();  
          37.   
          38.            Producer p = new Producer(ps, "生產者1");  
          39.   
          40.            Consumer c = new Consumer(ps, "消費者1");  
          41.   
          42.            new Thread(p).start();  
          43.   
          44.            new Thread(c).start();  
          45.   
          46.       }  
          47.   
          48. }  
          49. class Product {  
          50.   
          51.       int id;  
          52.       private String producedBy = "N/A";  
          53.   
          54.       private String consumedBy = "N/A";  
          55.   
          56.       // 構造函數,指明產品ID以及生產者名字。  
          57.   
          58.       Product(int id, String producedBy) {  
          59.   
          60.            this.id = id;  
          61.   
          62.            this.producedBy = producedBy;  
          63.   
          64.       }  
          65.   
          66.       // 消費,需要指明消費者名字  
          67.   
          68.       public void consume(String consumedBy) {  
          69.   
          70.            this.consumedBy = consumedBy;  
          71.   
          72.       }  
          73.   
          74.       public String toString() {  
          75.   
          76.            return "Product : " + id + ", produced by " + producedBy  
          77.   
          78.                       + ", consumed by " + consumedBy;  
          79.   
          80.       }  
          81.   
          82.       public String getProducedBy() {  
          83.   
          84.            return producedBy;  
          85.   
          86.       }  
          87.   
          88.       public void setProducedBy(String producedBy) {  
          89.   
          90.            this.producedBy = producedBy;  
          91.   
          92.       }  
          93.   
          94.       public String getConsumedBy() {  
          95.   
          96.            return consumedBy;  
          97.   
          98.       }  
          99.   
          100.       public void setConsumedBy(String consumedBy) {  
          101.   
          102.            this.consumedBy = consumedBy;  
          103.   
          104.       }  
          105. }  
          106.   
          107. // 這個class就是倉庫,是生產者跟消費者共同爭奪控制權的同步資源  
          108.   
          109. class ProductStack {  
          110.   
          111.       int index = 0;  
          112.   
          113.       Product[] arrProduct = new Product[6];  
          114.   
          115.       // push使用來讓生產者放置產品的  
          116.   
          117.       public synchronized void push(Product product) {  
          118.   
          119.            // 如果倉庫滿了  
          120.   
          121.            while (index == arrProduct.length) // 這里本來可以用if(),但是如果catch  
          122.   
          123.                                             // exception會出問題,讓滿的index越界  
          124.   
          125.            {  
          126.   
          127.                  try {  
          128.   
          129.                       // here, "this" means the thread that is using "push"  
          130.   
          131.                       // so in this case it's a producer thread instance.  
          132.   
          133.                       // the BIG difference between sleep() and wait() is, once  
          134.   
          135.                       // wait(),  
          136.   
          137.                       // the thread won't have the lock anymore  
          138.   
          139.                       // so when a producer wait() here, it will lost the lock of  
          140.   
          141.                       // "push()"  
          142.   
          143.                       // While sleep() is still keeping this lock  
          144.   
          145.                       // Important: wait() and notify() should be in "synchronized"  
          146.   
          147.                       // block  
          148.   
          149.                       System.out.println(product.getProducedBy() + " is waiting.");  
          150.   
          151.                       // 等待,并且從這里退出push()  
          152.   
          153.                       wait();  
          154.   
          155.                  } catch (InterruptedException e) {  
          156.   
          157.                       e.printStackTrace();  
          158.   
          159.                  }  
          160.   
          161.            }  
          162.   
          163.            System.out.println(product.getProducedBy() + " sent a notifyAll().");  
          164.   
          165.            // 因為我們不確定有沒有線程在wait(),所以我們既然生產了產品,就喚醒有可能等待的消費者,讓他們醒來,準備消費  
          166.   
          167.            notifyAll();  
          168.   
          169.            // 注意,notifyAll()以后,并沒有退出,而是繼續執行直到完成。  
          170.   
          171.            arrProduct[index] = product;  
          172.   
          173.            index++;  
          174.   
          175.            System.out.println(product.getProducedBy() + " 生產了: " + product);  
          176.   
          177.       }  
          178.   
          179.       // pop用來讓消費者取出產品的  
          180.   
          181.       public synchronized Product pop(String consumerName) {  
          182.   
          183.            // 如果倉庫空了  
          184.   
          185.            while (index == 0) {  
          186.   
          187.                  try {  
          188.   
          189.                       // here will be the consumer thread instance will be waiting ,  
          190.   
          191.                       // because empty  
          192.   
          193.                       System.out.println(consumerName + " is waiting.");  
          194.   
          195.                       // 等待,并且從這里退出pop()  
          196.   
          197.                       wait();  
          198.   
          199.                  } catch (InterruptedException e) {  
          200.   
          201.                       e.printStackTrace();  
          202.   
          203.                  }  
          204.   
          205.            }  
          206.   
          207.            System.out.println(consumerName + " sent a notifyAll().");  
          208.   
          209.            // 因為我們不確定有沒有線程在wait(),所以我們既然消費了產品,就喚醒有可能等待的生產者,讓他們醒來,準備生產  
          210.   
          211.            notifyAll();  
          212.   
          213.            // 注意,notifyAll()以后,并沒有退出,而是繼續執行直到完成。  
          214.   
          215.            // 取出產品  
          216.   
          217.            index--;  
          218.   
          219.            Product product = arrProduct[index];  
          220.   
          221.            product.consume(consumerName);  
          222.   
          223.            System.out.println(product.getConsumedBy() + " 消費了: " + product);  
          224.   
          225.            return product;  
          226.   
          227.       }  
          228.   
          229. }  
          230.   
          231. class Producer implements Runnable {  
          232.   
          233.       String name;  
          234.       ProductStack ps = null;  
          235.   
          236.       Producer(ProductStack ps, String name) {  
          237.   
          238.            this.ps = ps;  
          239.   
          240.            this.name = name;  
          241.   
          242.       }  
          243.   
          244.       public void run() {  
          245.   
          246.            for (int i = 0; i < 20; i++) {  
          247.   
          248.                  Product product = new Product(i, name);  
          249.   
          250.                  ps.push(product);  
          251.   
          252.                  try {  
          253.   
          254.                       Thread.sleep((int) (Math.random() * 200));  
          255.   
          256.                  } catch (InterruptedException e) {  
          257.   
          258.                       e.printStackTrace();  
          259.   
          260.                  }  
          261.   
          262.            }  
          263.   
          264.       }  
          265.   
          266. }  
          267.   
          268.   
          269. class Consumer implements Runnable {  
          270.   
          271.       String name;  
          272.       ProductStack ps = null;  
          273.       Consumer(ProductStack ps, String name) {  
          274.   
          275.            this.ps = ps;  
          276.   
          277.            this.name = name;  
          278.   
          279.       }  
          280.   
          281.       public void run() {  
          282.   
          283.            for (int i = 0; i < 20; i++) {  
          284.   
          285.                  Product product = ps.pop(name);  
          286.   
          287.                  try {  
          288.   
          289.                       Thread.sleep((int) (Math.random() * 1000));  
          290.   
          291.                  } catch (InterruptedException e) {  
          292.   
          293.                       e.printStackTrace();  
          294.   
          295.                  }  
          296.   
          297.            }  
          298.   
          299.       }  
          300.   
          301. }  

          posted on 2012-04-17 13:39 AlanLiu 閱讀(657) 評論(0)  編輯  收藏 所屬分類: java


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2012年4月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          導航

          統計

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 龙里县| 丰都县| 镇远县| 汪清县| 虎林市| 桃园市| 天台县| 贺州市| 湾仔区| 商丘市| 嘉鱼县| 仁化县| 肇庆市| 德安县| 天长市| 林口县| 齐齐哈尔市| 大方县| 延川县| 松桃| 离岛区| 岑巩县| 栖霞市| 金平| 东安县| 九台市| 衡水市| 延安市| 桐庐县| 师宗县| 乐亭县| 原阳县| 镇巴县| 同江市| 齐河县| 广安市| 迭部县| 忻城县| 广西| 明星| 历史|