- Timestamp:
- 2017-05-10T18:04:08+12:00 (7 years ago)
- Location:
- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/build
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone3/src/java/org/greenstone/gsdl3/build/CollectionConstructor.java
r31667 r31669 5 5 import org.greenstone.gsdl3.util.*; 6 6 //import java.util.Thread 7 import java x.swing.event.EventListenerList;7 import java.util.concurrent.CopyOnWriteArrayList; 8 8 import org.w3c.dom.Element; 9 9 … … 22 22 /** other arguments/parameters for the construction process - in a paramList */ 23 23 protected Element process_params = null; 24 /** the list of listeners for the process */ 25 protected EventListenerList listeners = null; 24 /** the list of listeners for the process. We need it to be threadsafe. 25 * see http://stackoverflow.com/questions/8259479/should-i-synchronize-listener-notifications-or-not 26 * https://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html 27 * "A thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are 28 * implemented by making a fresh copy of the underlying array. 29 * This is ordinarily too costly, but may be more efficient than alternatives when traversal operations 30 * vastly outnumber mutations, and is useful when you cannot or don't want to synchronize traversals, 31 * yet need to preclude interference among concurrent threads." 32 */ 33 protected final CopyOnWriteArrayList<ConstructionListener> listeners; 26 34 /** A flag used to determine if this process has been asked to cancel. */ 27 35 protected boolean cancel = false; // Not really used (in any way that works) … … 34 42 { 35 43 super(name); 36 this.listeners = new EventListenerList();44 this.listeners = new CopyOnWriteArrayList<ConstructionListener>(); 37 45 } 38 46 … … 87 95 public boolean addListener(ConstructionListener listener) 88 96 { 89 this.listeners.add(ConstructionListener.class,listener);90 97 this.listeners.add(listener); 98 return true; 91 99 } 92 100 93 101 public boolean removeListener(ConstructionListener listener) 94 { 95 this.listeners.remove(ConstructionListener.class,listener);96 102 { 103 this.listeners.remove(listener); 104 return true; 97 105 } 98 106 99 107 protected void sendProcessBegun(ConstructionEvent evt) 100 108 { 101 Object[] concerned = this.listeners.getListenerList(); 102 for (int i = 0; i < concerned.length; i += 2) 103 { 104 if (concerned[i] == ConstructionListener.class) 105 { 106 ((ConstructionListener) concerned[i + 1]).processBegun(evt); 107 } 108 } 109 // See http://stackoverflow.com/questions/8259479/should-i-synchronize-listener-notifications-or-not 110 for (ConstructionListener l: this.listeners) { 111 l.processBegun(evt); 112 } 109 113 } 110 114 111 115 protected void sendProcessComplete(ConstructionEvent evt) 112 116 { 113 Object[] concerned = this.listeners.getListenerList(); 114 for (int i = 0; i < concerned.length; i += 2) 115 { 116 if (concerned[i] == ConstructionListener.class) 117 { 118 ((ConstructionListener) concerned[i + 1]).processComplete(evt); 119 } 120 } 117 for (ConstructionListener l: this.listeners) { 118 l.processComplete(evt); 119 } 121 120 } 122 121 123 protected synchronized void sendProcessStatus(ConstructionEvent evt) 122 // Method doesn't need to be synchronized any more, since it uses the ThreadSafe CopyOnWriteArrayList 123 // for listeners list. 124 // See http://stackoverflow.com/questions/8259479/should-i-synchronize-listener-notifications-or-not 125 // See http://stackoverflow.com/questions/574240/is-there-an-advantage-to-use-a-synchronized-method-instead-of-a-synchronized-blo 126 protected void sendProcessStatus(ConstructionEvent evt) 124 127 { 125 126 Object[] concerned = this.listeners.getListenerList(); 127 for (int i = 0; i < concerned.length; i += 2) 128 { 129 if (concerned[i] == ConstructionListener.class) 130 { 131 ((ConstructionListener) concerned[i + 1]).processStatus(evt); 132 } 133 } 128 for (ConstructionListener l: this.listeners) { 129 l.processStatus(evt); 130 } 134 131 } 135 132 136 133 protected void sendMessage(ConstructionEvent evt) 137 134 { 138 139 Object[] concerned = this.listeners.getListenerList(); 140 for (int i = 0; i < concerned.length; i += 2) 141 { 142 if (concerned[i] == ConstructionListener.class) 143 { 144 ((ConstructionListener) concerned[i + 1]).message(evt); 145 } 146 } 135 for (ConstructionListener l: this.listeners) { 136 l.message(evt); 137 } 147 138 } 148 139 -
main/trunk/greenstone3/src/java/org/greenstone/gsdl3/build/GS2PerlConstructor.java
r31668 r31669 449 449 } 450 450 451 451 452 452 protected boolean runPerlCommand(String[] command, String[] envvars, File dir) 453 453 { … … 700 700 // exceptions when reading from our perl process' stderr and stdout streams are handled by 701 701 // SynchronizedProcessHandler.gotException() below, since they happen in separate threads 702 // from this one (the one from which the perl process is run). 703 public synchronized void gotException(Exception e) { 702 // from this one (the one from which the perl process is run). So this method's operations 703 // have been made thread-safe, rather than synchronizing on the method itself which locks 704 // *this* object and which isn't actually useful for what I want to do. 705 public void gotException(Exception e) { 704 706 705 707 // do what original runPerlCommand() code always did when an exception occurred … … 791 793 792 794 // this next method is thread safe since only synchronized methods are invoked. 793 // and only immutable (final) vars are used. NO, What about the listeners??? 794 // So have made this next method synchronized, which synchronizes on the GS2PerlConstructor 795 // and consequently its member variables are protected against concurrent access 796 // by multiple threads. 795 // and only immutable (final) vars are used. And the listeners of this class have 796 // now been made threadsafe by using CopyOnWriteArrayList in place of EventListenerList. 797 797 sendProcessStatus(new ConstructionEvent(GS2PerlConstructor.this, GSStatus.CONTINUING, line)); 798 798
Note:
See TracChangeset
for help on using the changeset viewer.