@@ -75,15 +75,19 @@ private static final class ObserveOnSubscriber<T> extends Subscriber<T> {
75
75
final NotificationLite <T > on = NotificationLite .instance ();
76
76
77
77
final Queue <Object > queue ;
78
- volatile boolean completed = false ;
79
- volatile boolean failure = false ;
78
+
79
+ // the status of the current stream
80
+ volatile boolean finished = false ;
80
81
82
+ @ SuppressWarnings ("unused" )
81
83
volatile long requested = 0 ;
84
+
82
85
@ SuppressWarnings ("rawtypes" )
83
86
static final AtomicLongFieldUpdater <ObserveOnSubscriber > REQUESTED = AtomicLongFieldUpdater .newUpdater (ObserveOnSubscriber .class , "requested" );
84
87
85
88
@ SuppressWarnings ("unused" )
86
89
volatile long counter ;
90
+
87
91
@ SuppressWarnings ("rawtypes" )
88
92
static final AtomicLongFieldUpdater <ObserveOnSubscriber > COUNTER_UPDATER = AtomicLongFieldUpdater .newUpdater (ObserveOnSubscriber .class , "counter" );
89
93
@@ -127,7 +131,7 @@ public void onStart() {
127
131
128
132
@ Override
129
133
public void onNext (final T t ) {
130
- if (isUnsubscribed () || completed ) {
134
+ if (isUnsubscribed ()) {
131
135
return ;
132
136
}
133
137
if (!queue .offer (on .next (t ))) {
@@ -139,30 +143,23 @@ public void onNext(final T t) {
139
143
140
144
@ Override
141
145
public void onCompleted () {
142
- if (isUnsubscribed () || completed ) {
146
+ if (isUnsubscribed () || finished ) {
143
147
return ;
144
148
}
145
- if (error != null ) {
146
- return ;
147
- }
148
- completed = true ;
149
+ finished = true ;
149
150
schedule ();
150
151
}
151
152
152
153
@ Override
153
154
public void onError (final Throwable e ) {
154
- if (isUnsubscribed () || completed ) {
155
- return ;
156
- }
157
- if (error != null ) {
155
+ if (isUnsubscribed () || finished ) {
158
156
return ;
159
157
}
160
158
error = e ;
161
159
// unsubscribe eagerly since time will pass before the scheduled onError results in an unsubscribe event
162
160
unsubscribe ();
163
- // mark failure so the polling thread will skip onNext still in the queue
164
- completed = true ;
165
- failure = true ;
161
+ finished = true ;
162
+ // polling thread should skip any onNext still in the queue
166
163
schedule ();
167
164
}
168
165
@@ -191,42 +188,51 @@ void pollQueue() {
191
188
*/
192
189
counter = 1 ;
193
190
194
- // middle:
195
191
while (!scheduledUnsubscribe .isUnsubscribed ()) {
196
- if (failure ) {
197
- child .onError (error );
198
- return ;
199
- } else {
200
- if (requested == 0 && completed && queue .isEmpty ()) {
192
+ if (finished ) {
193
+ // only read volatile error once
194
+ Throwable err = error ;
195
+ if (err != null ) {
196
+ // clear the queue to enable gc
197
+ queue .clear ();
198
+ // even if there are onNext in the queue we eagerly notify of error
199
+ child .onError (err );
200
+ return ;
201
+ } else if (queue .isEmpty ()) {
201
202
child .onCompleted ();
202
203
return ;
203
204
}
204
- if (REQUESTED .getAndDecrement (this ) != 0 ) {
205
- boolean c = completed ;
206
- Object o = queue .poll ();
207
- if (o == null ) {
208
- if (c ) {
209
- if (failure ) {
210
- child .onError (error );
211
- } else {
212
- child .onCompleted ();
213
- }
205
+ }
206
+ if (REQUESTED .getAndDecrement (this ) != 0 ) {
207
+ Object o = queue .poll ();
208
+ if (o == null ) {
209
+ // nothing in queue (but be careful, something could be added concurrently right now)
210
+ if (finished ) {
211
+ // only read volatile error once
212
+ Throwable err = error ;
213
+ if (err != null ) {
214
+ // clear the queue to enable gc
215
+ queue .clear ();
216
+ // even if there are onNext in the queue we eagerly notify of error
217
+ child .onError (err );
218
+ return ;
219
+ } else if (queue .isEmpty ()) {
220
+ child .onCompleted ();
214
221
return ;
215
- }
216
- // nothing in queue
217
- REQUESTED .incrementAndGet (this );
218
- break ;
219
- } else {
220
- if (!on .accept (child , o )) {
221
- // non-terminal event so let's increment count
222
- emitted ++;
223
222
}
224
223
}
225
- } else {
226
- // we hit the end ... so increment back to 0 again
227
224
REQUESTED .incrementAndGet (this );
228
225
break ;
226
+ } else {
227
+ if (!on .accept (child , o )) {
228
+ // non-terminal event so let's increment count
229
+ emitted ++;
230
+ }
229
231
}
232
+ } else {
233
+ // we hit the end ... so increment back to 0 again
234
+ REQUESTED .incrementAndGet (this );
235
+ break ;
230
236
}
231
237
}
232
238
} while (COUNTER_UPDATER .decrementAndGet (this ) > 0 );
0 commit comments