1. 程式人生 > >轉: 【Java並發編程】之十三:生產者—消費者模型(含代碼)

轉: 【Java並發編程】之十三:生產者—消費者模型(含代碼)

tool boolean 通知 阻塞 上一個 [] ble 否則 線程

轉載請註明出處:http://blog.csdn.net/ns_code/article/details/17249321

生產者消費者問題是線程模型中的經典問題:生產者和消費者在同一時間段內共用同一存儲空間,生產者向空間裏生產數據,而消費者取走數據。

這裏實現如下情況的生產--消費模型:

生產者不斷交替地生產兩組數據“姓名--1 --> 內容--1”,“姓名--2--> 內容--2”,消費者不斷交替地取得這兩組數據,這裏的姓名--1”和“姓名--2”模擬為數據的名稱,“內容--1 ”和“內容--2 ”模擬為數據的內容。

由於本程序中牽扯到線程運行的不確定性,因此可能會出現以下問題:

1、假設生產者線程剛向數據存儲空間添加了數據的名稱,還沒有加入該信息的內容,程序就切換到了消費者線程,消費者線程將把信息的名稱和上一個信息的內容聯系在一起;

2、生產者生產了若幹次數據,消費者才開始取數據,或者是,消費者取完一次數據後,還沒等生產者放入新的數據,又重復取出了已取過的數據。

問題1很明顯要靠同步來解決,問題2則需要線程間通信,生產者線程放入數據後,通知消費者線程取出數據,消費者線程取出數據後,通知生產者線程生產數據,這裏用wait/notify機制來實現。

詳細的實現代碼如下:

[java] view plain copy
  1. class Info{ // 定義信息類
  2. private String name = "name";//定義name屬性,為了與下面set的name屬性區別開
  3. private String content = "content" ;// 定義content屬性,為了與下面set的content屬性區別開
  4. private boolean flag = true ; // 設置標誌位,初始時先生產
  5. public synchronized void set(String name,String content){
  6. while(!flag){
  7. try{
  8. super.wait() ;
  9. }catch(InterruptedException e){
  10. e.printStackTrace() ;
  11. }
  12. }
  13. this.setName(name) ; // 設置名稱
  14. try{
  15. Thread.sleep(300) ;
  16. }catch(InterruptedException e){
  17. e.printStackTrace() ;
  18. }
  19. this.setContent(content) ; // 設置內容
  20. flag = false ; // 改變標誌位,表示可以取走
  21. super.notify();
  22. }
  23. public synchronized void get(){
  24. while(flag){
  25. try{
  26. super.wait() ;
  27. }catch(InterruptedException e){
  28. e.printStackTrace() ;
  29. }
  30. }
  31. try{
  32. Thread.sleep(300) ;
  33. }catch(InterruptedException e){
  34. e.printStackTrace() ;
  35. }
  36. System.out.println(this.getName() +
  37. " --> " + this.getContent()) ;
  38. flag = true ; // 改變標誌位,表示可以生產
  39. super.notify();
  40. }
  41. public void setName(String name){
  42. this.name = name ;
  43. }
  44. public void setContent(String content){
  45. this.content = content ;
  46. }
  47. public String getName(){
  48. return this.name ;
  49. }
  50. public String getContent(){
  51. return this.content ;
  52. }
  53. }
  54. class Producer implements Runnable{ // 通過Runnable實現多線程
  55. private Info info = null ; // 保存Info引用
  56. public Producer(Info info){
  57. this.info = info ;
  58. }
  59. public void run(){
  60. boolean flag = true ; // 定義標記位
  61. for(int i=0;i<10;i++){
  62. if(flag){
  63. this.info.set("姓名--1","內容--1") ; // 設置名稱
  64. flag = false ;
  65. }else{
  66. this.info.set("姓名--2","內容--2") ; // 設置名稱
  67. flag = true ;
  68. }
  69. }
  70. }
  71. }
  72. class Consumer implements Runnable{
  73. private Info info = null ;
  74. public Consumer(Info info){
  75. this.info = info ;
  76. }
  77. public void run(){
  78. for(int i=0;i<10;i++){
  79. this.info.get() ;
  80. }
  81. }
  82. }
  83. public class ThreadCaseDemo03{
  84. public static void main(String args[]){
  85. Info info = new Info(); // 實例化Info對象
  86. Producer pro = new Producer(info) ; // 生產者
  87. Consumer con = new Consumer(info) ; // 消費者
  88. new Thread(pro).start() ;
  89. //啟動了生產者線程後,再啟動消費者線程
  90. try{
  91. Thread.sleep(500) ;
  92. }catch(InterruptedException e){
  93. e.printStackTrace() ;
  94. }
  95. new Thread(con).start() ;
  96. }
  97. }


執行結果如下:

技術分享

另外,在run方法中,二者循環的次數要相同,否則,當一方的循環結束時,另一方的循環依然繼續,它會阻塞在wait()方法處,而等不到對方的notify通知。

轉: 【Java並發編程】之十三:生產者—消費者模型(含代碼)