|
19 | 19 | import static org.mockito.Mockito.*;
|
20 | 20 |
|
21 | 21 | import java.util.Arrays;
|
22 |
| -import java.util.HashMap; |
23 |
| -import java.util.HashSet; |
24 | 22 | import java.util.LinkedList;
|
25 | 23 | import java.util.List;
|
26 | 24 | import java.util.Map;
|
27 |
| -import java.util.Set; |
| 25 | +import java.util.concurrent.ConcurrentHashMap; |
28 | 26 | import java.util.concurrent.atomic.AtomicBoolean;
|
29 | 27 | import java.util.concurrent.atomic.AtomicInteger;
|
30 | 28 |
|
@@ -96,7 +94,7 @@ public CombineObserver(Aggregator<R> a, Observable<T> w) {
|
96 | 94 | this.w = w;
|
97 | 95 | }
|
98 | 96 |
|
99 |
| - public synchronized void startWatching() { |
| 97 | + private void startWatching() { |
100 | 98 | if (subscription != null) {
|
101 | 99 | throw new RuntimeException("This should only be called once.");
|
102 | 100 | }
|
@@ -134,23 +132,11 @@ private static class Aggregator<R> implements Func1<Observer<R>, Subscription> {
|
134 | 132 | // Stores how many observers have already completed
|
135 | 133 | private final AtomicInteger numCompleted = new AtomicInteger(0);
|
136 | 134 |
|
137 |
| - // Used as an internal lock for handling the latest values of each observer |
138 |
| - private final Object lockObject = new Object(); |
139 |
| - |
140 | 135 | /**
|
141 |
| - * The latest value from each observer |
142 |
| - * <p> |
143 |
| - * Note that access to this set MUST BE SYNCHRONIZED via 'lockObject' above. |
144 |
| - * */ |
145 |
| - private final Map<CombineObserver<R, ?>, Object> latestValue = new HashMap<CombineObserver<R, ?>, Object>(); |
| 136 | + * The latest value from each observer. |
| 137 | + */ |
| 138 | + private final Map<CombineObserver<R, ?>, Object> latestValue = new ConcurrentHashMap<CombineObserver<R, ?>, Object>(); |
146 | 139 |
|
147 |
| - /** |
148 |
| - * Whether each observer has a latest value at all. |
149 |
| - * <p> |
150 |
| - * Note that access to this set MUST BE SYNCHRONIZED via 'lockObject' above. |
151 |
| - * */ |
152 |
| - private final Set<CombineObserver<R, ?>> hasLatestValue = new HashSet<CombineObserver<R, ?>>(); |
153 |
| - |
154 | 140 | /**
|
155 | 141 | * Ordered list of observers to combine.
|
156 | 142 | * No synchronization is necessary as these can not be added or changed asynchronously.
|
@@ -215,31 +201,20 @@ <T> void next(CombineObserver<R, T> w, T arg) {
|
215 | 201 | return;
|
216 | 202 | }
|
217 | 203 |
|
218 |
| - // define here so the variable is out of the synchronized scope |
| 204 | + // remember this as the latest value for this observer |
| 205 | + latestValue.put(w, arg); |
| 206 | + |
| 207 | + if (latestValue.size() < observers.size()) { |
| 208 | + // we don't have a value yet for each observer to combine, so we don't have a combined value yet either |
| 209 | + return; |
| 210 | + } |
| 211 | + |
219 | 212 | Object[] argsToCombineLatest = new Object[observers.size()];
|
220 |
| - |
221 |
| - // we synchronize everything that touches latest values |
222 |
| - synchronized (lockObject) { |
223 |
| - // remember this as the latest value for this observer |
224 |
| - latestValue.put(w, arg); |
225 |
| - |
226 |
| - // remember that this observer now has a latest value set |
227 |
| - hasLatestValue.add(w); |
228 |
| - |
229 |
| - if (hasLatestValue.size() < observers.size()) { |
230 |
| - // we don't have a value yet for each observer to combine, so we don't have a combined value yet either |
231 |
| - return; |
232 |
| - } |
233 |
| - |
234 |
| - // if we get to here this means all the observers have a latest value |
235 |
| - int i = 0; |
236 |
| - for (CombineObserver<R, ?> _w : observers) { |
237 |
| - argsToCombineLatest[i++] = latestValue.get(_w); |
238 |
| - } |
| 213 | + int i = 0; |
| 214 | + for (CombineObserver<R, ?> _w : observers) { |
| 215 | + argsToCombineLatest[i++] = latestValue.get(_w); |
239 | 216 | }
|
240 |
| - // if we did not return above from the synchronized block we can now invoke the combineLatestFunction with all of the args |
241 |
| - // we do this outside the synchronized block as it is now safe to call this concurrently and don't need to block other threads from calling |
242 |
| - // this 'next' method while another thread finishes calling this combineLatestFunction |
| 217 | + |
243 | 218 | try {
|
244 | 219 | R combinedValue = combineLatestFunction.call(argsToCombineLatest);
|
245 | 220 | observer.onNext(combinedValue);
|
|
0 commit comments