Fork me on GitHub
多线程编程答案篇(C#和Java):解决pull和push模式在同一个程序中的冲突

大家应该对生产者消费者模式都耳熟能详了吧,在push模式上建立pull模式(或者说把push模式转换成pull模式)和生产者消费者模式一样,都是在并发环境里的设计模式。我今后会在博客里介绍更多的并发设计模式(不仅仅限于多线程并发设计模式),很多都将会是原创的。

今天就先发个上周挑战题的参考答案,分析再稍后几天。我这里说的分析是指对模式的分析,源代码就不一一分析了,但你有问题并留了言的话,我是会答复的。

C#的部分代码在上周的帖子里(C#多线程编程擂台赛:解决pull和push模式在同一个程序中的冲突),Java的答案就全在这里了。

C#: PullOnPushReader.cs
1 using System;
  2 using System.Collections;
  3 using System.Collections.Generic;
  4 using System.Threading;
  5 
  6 namespace CodingChallenge
  7 {
  8     public class PullOnPushReader
  9     {
 10         private PushReaderAgent current;
 11      
 12         public IEnumerator GetEnumerator ()
 13         {
 14             Close ();
 15             return current = new PushReaderAgent ();
 16         }
 17 
 18         public void Close ()
 19         {
 20             if (current != null) {
 21                 current.Close ();
 22                 current = null;
 23             }
 24         }
 25     }
 26  
 27     class PushReaderAgent : IEnumerator
 28     {
 29         private PushReader pushReader;
 30         private bool readerToStop, readerStopped;
 31         private Exception readerError;
 32         private string current;
 33      
 34         // user thread
 35         public PushReaderAgent ()
 36         {
 37             pushReader = new PushReader ();
 38             pushReader.Handler += OnNewItem;
 39             
 40             Thread pushReaderThread = new Thread (new ThreadStart (RunPushReader));
 41             lock (this) {
 42                 pushReaderThread.Start ();
 43                 Monitor.Wait (this);
 44             }
 45         }
 46      
 47         public void Reset ()
 48         {
 49             throw new InvalidOperationException ("not a full implementation");
 50         }
 51 
 52         // user thread
 53         public bool MoveNext ()
 54         {
 55             lock (this) {
 56                 Monitor.Pulse (this);
 57                 Monitor.Wait (this);
 58                 
 59                 if (readerStopped) {
 60                     if (readerError != null) 
 61                         throw readerError;
 62                     else
 63                         return false;
 64                 }
 65                 
 66                 return true;
 67             }
 68         }
 69 
 70         // user thread
 71         public object Current {
 72             get {
 73                 lock (this) {
 74                     return current;
 75                 }
 76             }
 77         }
 78 
 79         // user thread
 80         public void Close ()
 81         {
 82             lock (this) {
 83                 readerToStop = true;
 84                 Monitor.Pulse (this);
 85             }
 86         }
 87      
 88         // reader thread
 89         private void RunPushReader ()
 90         {
 91             Exception error = null;
 92             try {
 93                 lock (this) {
 94                     Monitor.Pulse (this);
 95                     Monitor.Wait (this);
 96                     
 97                     if (readerToStop) {
 98                         return;
 99                     }
100                 }
101                 
102                 pushReader.Start ();
103                 
104             } catch (Exception e) {
105                 error = e;
106             } finally {
107                 lock (this) {
108                     readerStopped = true;
109                     readerError = error;
110                  
111                     Monitor.Pulse (this);
112                 }
113             }
114         }
115      
116         // reader thread
117         private void OnNewItem (string item)
118         {
119             lock (this) {
120                 current = item;
121              
122                 Monitor.Pulse (this);
123                 Monitor.Wait (this);
124                 
125                 if (readerToStop) {
126                     throw new Exception ("stop myself");
127                 }
128             }
129         }
130     }
131 }
Java: MainClass.java
 1 package CodingChallenge;
 2 
 3 import java.util.Enumeration;
 4 
 5 public class MainClass {
 6 
 7     public static void main (String[] args) {
 8 
 9         PullOnPushReader popReader = new PullOnPushReader ();
10 
11         Enumeration<String> itemEnumerator = popReader.getEnumeration ();
12 
13         while (true) {
14             System.out.println ("Caller: asking for next...");
15             if (!itemEnumerator.hasMoreElements ()) {
16                 System.out.println ("Caller: reached the end");
17                 break;
18             }
19 
20             String item = itemEnumerator.nextElement ();
21             System.out.println ("Caller: found " + item);
22             System.out.println ();
23 
24             if (item.startsWith ("zzz")) {
25                 break;
26             }
27         }
28 
29         System.out.println ("Caller: closing PullOnPushReader...");
30         popReader.close ();
31     }
32 }
Java: PullOnPushReader.java
1 package CodingChallenge;
 2 
 3 import java.util.Enumeration;
 4 
 5 public class PullOnPushReader {
 6 
 7     private PushReaderAgent current;
 8 
 9     public Enumeration<String> getEnumeration () {
10         close ();
11         return current = new PushReaderAgent ();
12     }
13 
14     public void close () {
15         if (current != null) {
16             current.close ();
17             current = null;
18         }
19     }
20 
21 }
Java: PushReader.java
 1 package CodingChallenge;
 2 
 3 import java.io.*;
 4 
 5 import org.xml.sax.*;
 6 import org.xml.sax.helpers.*;
 7 
 8 public class PushReader extends DefaultHandler {
 9 
10     public static interface Listener {
11         void onItem (String item) throws Exception;
12     }
13 
14     private Listener listener;
15     private XMLReader xmlReader;
16     private InputSource xmlSource;
17 
18     public PushReader (Listener listener) {
19         this.listener = listener;
20     }
21 
22     public void start () throws Exception {
23         System.out.println ("    PushReader - started");
24 
25         xmlReader = XMLReaderFactory.createXMLReader ();
26         xmlReader.setContentHandler (this);
27         xmlSource = new InputSource (new FileInputStream ("exchange-rate.xml"));
28 
29         try {
30 
31             xmlReader.parse (xmlSource);
32 
33         } catch (Exception e) {
34             xmlSource.getByteStream ().close ();
35             if (e.getMessage ().equals ("stop myself")) {
36                 System.out.println ("    PushReader - user wants to stop");
37             } else {
38                 throw e;
39             }
40         }
41 
42         System.out.println ("    PushReader - closed");
43     }
44 
45     public void startElement (String uri, String localName, String qName, Attributes attributes) throws SAXException {
46         if (qName.equals ("Cube")) {
47             String item = attributes.getValue ("currency") + ":" + attributes.getValue ("rate");
48             System.out.println ("    PushReader - read from xml: " + item);
49 
50             try {
51                 listener.onItem (item);
52             } catch (Exception e) {
53                 throw new SAXException (e.getMessage ());
54             }
55         }
56     }
57 }
Java: PushReaderAgent.java
1 package CodingChallenge;
  2 
  3 import java.util.Enumeration;
  4 
  5 public class PushReaderAgent implements Enumeration<String>, PushReader.Listener, Runnable {
  6 
  7     private PushReader pushReader;
  8     private boolean readerToStop, readerStopped;
  9     private Exception readerError;
 10     private String current;
 11 
 12     // user thread
 13     public PushReaderAgent () {
 14         synchronized (this) {
 15             pushReader = new PushReader (this);
 16 
 17             new Thread (this).start ();
 18 
 19             try {
 20                 this.wait ();
 21             } catch (InterruptedException e) {
 22             }
 23         }
 24     }
 25 
 26     // user thread
 27     public boolean hasMoreElements () {
 28         synchronized (this) {
 29             this.notify ();
 30             try {
 31                 this.wait ();
 32             } catch (InterruptedException e) {
 33             }
 34 
 35             if (readerStopped) {
 36                 if (readerError != null)
 37                     throw new RuntimeException (readerError);
 38                 else
 39                     return false;
 40             }
 41 
 42             return true;
 43         }
 44     }
 45 
 46     // user thread
 47     public String nextElement () {
 48         synchronized (this) {
 49             return current;
 50         }
 51     }
 52 
 53     // user thread
 54     public void close () {
 55         synchronized (this) {
 56             readerToStop = true;
 57             this.notify ();
 58         }
 59     }
 60 
 61     // reader thread
 62     public void run () {
 63         Exception error = null;
 64         try {
 65             synchronized (this) {
 66                 this.notify ();
 67                 this.wait ();
 68 
 69                 if (readerToStop) {
 70                     return;
 71                 }
 72             }
 73 
 74             pushReader.start ();
 75 
 76         } catch (Exception e) {
 77             error = e;
 78         } finally {
 79             synchronized (this) {
 80                 readerStopped = true;
 81                 readerError = error;
 82 
 83                 this.notify ();
 84             }
 85         }
 86     }
 87 
 88     // reader thread
 89     public void onItem (String item) throws Exception {
 90         synchronized (this) {
 91             current = item;
 92 
 93             this.notify ();
 94             this.wait ();
 95 
 96             if (readerToStop) {
 97                 throw new Exception ("stop myself");
 98             }
 99         }
100     }
101 }

 

posted on 2012-12-18 17:47  HackerVirus  阅读(307)  评论(0)    收藏  举报