Skip to content

Commit ab6dbc1

Browse files
akarnokdzsxwing
authored andcommitted
1.x: remove remaining field updaters (#3979)
This PR removes the remaining AtomicXFieldUpdaters from the library because reflection is somewhat problematic on Android. This also deprecates the internal BackpressureUtils.getAndAddRequest to indicate requested field updater should not be used anymore.
1 parent 4b61060 commit ab6dbc1

8 files changed

+90
-121
lines changed

src/main/java/rx/internal/operators/BackpressureUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ private BackpressureUtils() {
4545
* @param n
4646
* the number of requests to add to the requested count
4747
* @return requested value just prior to successful addition
48+
* @deprecated Android has issues with reflection-based atomics
4849
*/
50+
@Deprecated
4951
public static <T> long getAndAddRequest(AtomicLongFieldUpdater<T> requested, T object, long n) {
5052
// add n to field but check for overflow
5153
while (true) {

src/main/java/rx/internal/operators/CompletableOnSubscribeConcat.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,7 @@ static final class CompletableConcatSubscriber
5252

5353
volatile boolean done;
5454

55-
volatile int once;
56-
static final AtomicIntegerFieldUpdater<CompletableConcatSubscriber> ONCE =
57-
AtomicIntegerFieldUpdater.newUpdater(CompletableConcatSubscriber.class, "once");
55+
final AtomicBoolean once;
5856

5957
final ConcatInnerSubscriber inner;
6058

@@ -67,6 +65,7 @@ public CompletableConcatSubscriber(CompletableSubscriber actual, int prefetch) {
6765
this.sr = new SerialSubscription();
6866
this.inner = new ConcatInnerSubscriber();
6967
this.wip = new AtomicInteger();
68+
this.once = new AtomicBoolean();
7069
add(sr);
7170
request(prefetch);
7271
}
@@ -84,7 +83,7 @@ public void onNext(Completable t) {
8483

8584
@Override
8685
public void onError(Throwable t) {
87-
if (ONCE.compareAndSet(this, 0, 1)) {
86+
if (once.compareAndSet(false, true)) {
8887
actual.onError(t);
8988
return;
9089
}
@@ -121,7 +120,7 @@ void next() {
121120
Completable c = queue.poll();
122121
if (c == null) {
123122
if (d) {
124-
if (ONCE.compareAndSet(this, 0, 1)) {
123+
if (once.compareAndSet(false, true)) {
125124
actual.onCompleted();
126125
}
127126
return;

src/main/java/rx/internal/operators/CompletableOnSubscribeMerge.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,9 @@ static final class CompletableMergeSubscriber
5555

5656
volatile boolean done;
5757

58-
volatile Queue<Throwable> errors;
59-
@SuppressWarnings("rawtypes")
60-
static final AtomicReferenceFieldUpdater<CompletableMergeSubscriber, Queue> ERRORS =
61-
AtomicReferenceFieldUpdater.newUpdater(CompletableMergeSubscriber.class, Queue.class, "errors");
58+
final AtomicReference<Queue<Throwable>> errors;
6259

63-
volatile int once;
64-
static final AtomicIntegerFieldUpdater<CompletableMergeSubscriber> ONCE =
65-
AtomicIntegerFieldUpdater.newUpdater(CompletableMergeSubscriber.class, "once");
60+
final AtomicBoolean once;
6661

6762
final AtomicInteger wip;
6863

@@ -72,6 +67,8 @@ public CompletableMergeSubscriber(CompletableSubscriber actual, int maxConcurren
7267
this.delayErrors = delayErrors;
7368
this.set = new CompositeSubscription();
7469
this.wip = new AtomicInteger(1);
70+
this.once = new AtomicBoolean();
71+
this.errors = new AtomicReference<Queue<Throwable>>();
7572
if (maxConcurrency == Integer.MAX_VALUE) {
7673
request(Long.MAX_VALUE);
7774
} else {
@@ -80,17 +77,17 @@ public CompletableMergeSubscriber(CompletableSubscriber actual, int maxConcurren
8077
}
8178

8279
Queue<Throwable> getOrCreateErrors() {
83-
Queue<Throwable> q = errors;
80+
Queue<Throwable> q = errors.get();
8481

8582
if (q != null) {
8683
return q;
8784
}
8885

8986
q = new ConcurrentLinkedQueue<Throwable>();
90-
if (ERRORS.compareAndSet(this, null, q)) {
87+
if (errors.compareAndSet(null, q)) {
9188
return q;
9289
}
93-
return errors;
90+
return errors.get();
9491
}
9592

9693
@Override
@@ -167,23 +164,23 @@ public void onCompleted() {
167164

168165
void terminate() {
169166
if (wip.decrementAndGet() == 0) {
170-
Queue<Throwable> q = errors;
167+
Queue<Throwable> q = errors.get();
171168
if (q == null || q.isEmpty()) {
172169
actual.onCompleted();
173170
} else {
174171
Throwable e = collectErrors(q);
175-
if (ONCE.compareAndSet(this, 0, 1)) {
172+
if (once.compareAndSet(false, true)) {
176173
actual.onError(e);
177174
} else {
178175
RxJavaPlugins.getInstance().getErrorHandler().handleError(e);
179176
}
180177
}
181178
} else
182179
if (!delayErrors) {
183-
Queue<Throwable> q = errors;
180+
Queue<Throwable> q = errors.get();
184181
if (q != null && !q.isEmpty()) {
185182
Throwable e = collectErrors(q);
186-
if (ONCE.compareAndSet(this, 0, 1)) {
183+
if (once.compareAndSet(false, true)) {
187184
actual.onError(e);
188185
} else {
189186
RxJavaPlugins.getInstance().getErrorHandler().handleError(e);

src/main/java/rx/internal/operators/OperatorGroupBy.java

Lines changed: 40 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -106,28 +106,16 @@ public static final class GroupBySubscriber<T, K, V>
106106

107107
final ProducerArbiter s;
108108

109-
volatile int cancelled;
110-
@SuppressWarnings("rawtypes")
111-
static final AtomicIntegerFieldUpdater<GroupBySubscriber> CANCELLED =
112-
AtomicIntegerFieldUpdater.newUpdater(GroupBySubscriber.class, "cancelled");
109+
final AtomicBoolean cancelled;
113110

114-
volatile long requested;
115-
@SuppressWarnings("rawtypes")
116-
static final AtomicLongFieldUpdater<GroupBySubscriber> REQUESTED =
117-
AtomicLongFieldUpdater.newUpdater(GroupBySubscriber.class, "requested");
118-
119-
volatile int groupCount;
120-
@SuppressWarnings("rawtypes")
121-
static final AtomicIntegerFieldUpdater<GroupBySubscriber> GROUP_COUNT =
122-
AtomicIntegerFieldUpdater.newUpdater(GroupBySubscriber.class, "groupCount");
111+
final AtomicLong requested;
112+
113+
final AtomicInteger groupCount;
123114

124115
Throwable error;
125116
volatile boolean done;
126117

127-
volatile int wip;
128-
@SuppressWarnings("rawtypes")
129-
static final AtomicIntegerFieldUpdater<GroupBySubscriber> WIP =
130-
AtomicIntegerFieldUpdater.newUpdater(GroupBySubscriber.class, "wip");
118+
final AtomicInteger wip;
131119

132120
public GroupBySubscriber(Subscriber<? super GroupedObservable<K, V>> actual, Func1<? super T, ? extends K> keySelector, Func1<? super T, ? extends V> valueSelector, int bufferSize, boolean delayError) {
133121
this.actual = actual;
@@ -137,10 +125,13 @@ public GroupBySubscriber(Subscriber<? super GroupedObservable<K, V>> actual, Fun
137125
this.delayError = delayError;
138126
this.groups = new ConcurrentHashMap<Object, GroupedUnicast<K, V>>();
139127
this.queue = new ConcurrentLinkedQueue<GroupedObservable<K, V>>();
140-
GROUP_COUNT.lazySet(this, 1);
141128
this.s = new ProducerArbiter();
142129
this.s.request(bufferSize);
143130
this.producer = new GroupByProducer(this);
131+
this.cancelled = new AtomicBoolean();
132+
this.requested = new AtomicLong();
133+
this.groupCount = new AtomicInteger(1);
134+
this.wip = new AtomicInteger();
144135
}
145136

146137
@Override
@@ -172,11 +163,11 @@ public void onNext(T t) {
172163
if (group == null) {
173164
// if the main has been cancelled, stop creating groups
174165
// and skip this value
175-
if (cancelled == 0) {
166+
if (!cancelled.get()) {
176167
group = GroupedUnicast.createWith(key, bufferSize, this, delayError);
177168
groups.put(mapKey, group);
178169

179-
GROUP_COUNT.getAndIncrement(this);
170+
groupCount.getAndIncrement();
180171

181172
notNew = false;
182173
q.offer(group);
@@ -210,7 +201,7 @@ public void onError(Throwable t) {
210201
}
211202
error = t;
212203
done = true;
213-
GROUP_COUNT.decrementAndGet(this);
204+
groupCount.decrementAndGet();
214205
drain();
215206
}
216207

@@ -226,7 +217,7 @@ public void onCompleted() {
226217
groups.clear();
227218

228219
done = true;
229-
GROUP_COUNT.decrementAndGet(this);
220+
groupCount.decrementAndGet();
230221
drain();
231222
}
232223

@@ -235,15 +226,15 @@ public void requestMore(long n) {
235226
throw new IllegalArgumentException("n >= 0 required but it was " + n);
236227
}
237228

238-
BackpressureUtils.getAndAddRequest(REQUESTED, this, n);
229+
BackpressureUtils.getAndAddRequest(requested, n);
239230
drain();
240231
}
241232

242233
public void cancel() {
243234
// cancelling the main source means we don't want any more groups
244235
// but running groups still require new values
245-
if (CANCELLED.compareAndSet(this, 0, 1)) {
246-
if (GROUP_COUNT.decrementAndGet(this) == 0) {
236+
if (cancelled.compareAndSet(false, true)) {
237+
if (groupCount.decrementAndGet() == 0) {
247238
unsubscribe();
248239
}
249240
}
@@ -252,14 +243,14 @@ public void cancel() {
252243
public void cancel(K key) {
253244
Object mapKey = key != null ? key : NULL_KEY;
254245
if (groups.remove(mapKey) != null) {
255-
if (GROUP_COUNT.decrementAndGet(this) == 0) {
246+
if (groupCount.decrementAndGet() == 0) {
256247
unsubscribe();
257248
}
258249
}
259250
}
260251

261252
void drain() {
262-
if (WIP.getAndIncrement(this) != 0) {
253+
if (wip.getAndIncrement() != 0) {
263254
return;
264255
}
265256

@@ -274,7 +265,7 @@ void drain() {
274265
return;
275266
}
276267

277-
long r = requested;
268+
long r = requested.get();
278269
boolean unbounded = r == Long.MAX_VALUE;
279270
long e = 0L;
280271

@@ -301,12 +292,12 @@ void drain() {
301292

302293
if (e != 0L) {
303294
if (!unbounded) {
304-
REQUESTED.addAndGet(this, e);
295+
requested.addAndGet(e);
305296
}
306297
s.request(-e);
307298
}
308299

309-
missed = WIP.addAndGet(this, -missed);
300+
missed = wip.addAndGet(-missed);
310301
if (missed == 0) {
311302
break;
312303
}
@@ -378,35 +369,27 @@ static final class State<T, K> extends AtomicInteger implements Producer, Subscr
378369
final GroupBySubscriber<?, K, T> parent;
379370
final boolean delayError;
380371

381-
volatile long requested;
382-
@SuppressWarnings("rawtypes")
383-
static final AtomicLongFieldUpdater<State> REQUESTED =
384-
AtomicLongFieldUpdater.newUpdater(State.class, "requested");
372+
final AtomicLong requested;
385373

386374
volatile boolean done;
387375
Throwable error;
388376

389-
volatile int cancelled;
390-
@SuppressWarnings("rawtypes")
391-
static final AtomicIntegerFieldUpdater<State> CANCELLED =
392-
AtomicIntegerFieldUpdater.newUpdater(State.class, "cancelled");
393-
394-
volatile Subscriber<? super T> actual;
395-
@SuppressWarnings("rawtypes")
396-
static final AtomicReferenceFieldUpdater<State, Subscriber> ACTUAL =
397-
AtomicReferenceFieldUpdater.newUpdater(State.class, Subscriber.class, "actual");
377+
final AtomicBoolean cancelled;
378+
379+
final AtomicReference<Subscriber<? super T>> actual;
398380

399-
volatile int once;
400-
@SuppressWarnings("rawtypes")
401-
static final AtomicIntegerFieldUpdater<State> ONCE =
402-
AtomicIntegerFieldUpdater.newUpdater(State.class, "once");
381+
final AtomicBoolean once;
403382

404383

405384
public State(int bufferSize, GroupBySubscriber<?, K, T> parent, K key, boolean delayError) {
406385
this.queue = new ConcurrentLinkedQueue<Object>();
407386
this.parent = parent;
408387
this.key = key;
409388
this.delayError = delayError;
389+
this.cancelled = new AtomicBoolean();
390+
this.actual = new AtomicReference<Subscriber<? super T>>();
391+
this.once = new AtomicBoolean();
392+
this.requested = new AtomicLong();
410393
}
411394

412395
@Override
@@ -415,19 +398,19 @@ public void request(long n) {
415398
throw new IllegalArgumentException("n >= required but it was " + n);
416399
}
417400
if (n != 0L) {
418-
BackpressureUtils.getAndAddRequest(REQUESTED, this, n);
401+
BackpressureUtils.getAndAddRequest(requested, n);
419402
drain();
420403
}
421404
}
422405

423406
@Override
424407
public boolean isUnsubscribed() {
425-
return cancelled != 0;
408+
return cancelled.get();
426409
}
427410

428411
@Override
429412
public void unsubscribe() {
430-
if (CANCELLED.compareAndSet(this, 0, 1)) {
413+
if (cancelled.compareAndSet(false, true)) {
431414
if (getAndIncrement() == 0) {
432415
parent.cancel(key);
433416
}
@@ -436,10 +419,10 @@ public void unsubscribe() {
436419

437420
@Override
438421
public void call(Subscriber<? super T> s) {
439-
if (ONCE.compareAndSet(this, 0, 1)) {
422+
if (once.compareAndSet(false, true)) {
440423
s.add(this);
441424
s.setProducer(this);
442-
ACTUAL.lazySet(this, s);
425+
actual.lazySet(s);
443426
drain();
444427
} else {
445428
s.onError(new IllegalStateException("Only one Subscriber allowed!"));
@@ -475,15 +458,15 @@ void drain() {
475458

476459
final Queue<Object> q = queue;
477460
final boolean delayError = this.delayError;
478-
Subscriber<? super T> a = actual;
461+
Subscriber<? super T> a = actual.get();
479462
NotificationLite<T> nl = NotificationLite.instance();
480463
for (;;) {
481464
if (a != null) {
482465
if (checkTerminated(done, q.isEmpty(), a, delayError)) {
483466
return;
484467
}
485468

486-
long r = requested;
469+
long r = requested.get();
487470
boolean unbounded = r == Long.MAX_VALUE;
488471
long e = 0;
489472

@@ -508,7 +491,7 @@ void drain() {
508491

509492
if (e != 0L) {
510493
if (!unbounded) {
511-
REQUESTED.addAndGet(this, e);
494+
requested.addAndGet(e);
512495
}
513496
parent.s.request(-e);
514497
}
@@ -519,13 +502,13 @@ void drain() {
519502
break;
520503
}
521504
if (a == null) {
522-
a = actual;
505+
a = actual.get();
523506
}
524507
}
525508
}
526509

527510
boolean checkTerminated(boolean d, boolean empty, Subscriber<? super T> a, boolean delayError) {
528-
if (cancelled != 0) {
511+
if (cancelled.get()) {
529512
queue.clear();
530513
parent.cancel(key);
531514
return true;

0 commit comments

Comments
 (0)