大家应该对生产者消费者模式都耳熟能详了吧,在push模式上建立pull模式(或者说把push模式转换成pull模式)和生产者消费者模式一样,都是在并发环境里的设计模式。我今后会在博客里介绍更多的并发设计模式(不仅仅限于多线程并发设计模式),很多都将会是原创的。
今天就先发个上周挑战题的参考答案,分析再稍后几天。我这里说的分析是指对模式的分析,源代码就不一一分析了,但你有问题并留了言的话,我是会答复的。
C#的部分代码在上周的帖子里(C#多线程编程擂台赛:解决pull和push模式在同一个程序中的冲突),Java的答案就全在这里了。
C#: PullOnPushReader.cs1 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.java1 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.java1 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.java1 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.java1 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 }
浙公网安备 33010602011771号