rx.internal.operators.OperatorMergeMaxConcurrent Maven / Gradle / Ivy
Show all versions of rxjava-core Show documentation
/**
* Copyright 2014 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package rx.internal.operators;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import rx.Observable;
import rx.Observable.Operator;
import rx.Subscriber;
import rx.observers.SerializedSubscriber;
import rx.subscriptions.CompositeSubscription;
/**
* Flattens a list of Observables into one Observable sequence, without any transformation.
*
*
*
* You can combine the items emitted by multiple Observables so that they act like a single
* Observable, by using the merge operation.
*
* @param the emitted value type
*/
public final class OperatorMergeMaxConcurrent implements Operator> {
final int maxConcurrency;
public OperatorMergeMaxConcurrent(int maxConcurrency) {
this.maxConcurrency = maxConcurrency;
}
@Override
public Subscriber super Observable extends T>> call(Subscriber super T> child) {
final SerializedSubscriber s = new SerializedSubscriber(child);
final CompositeSubscription csub = new CompositeSubscription();
child.add(csub);
return new SourceSubscriber(maxConcurrency, s, csub);
}
static final class SourceSubscriber extends Subscriber> {
final int maxConcurrency;
final Subscriber s;
final CompositeSubscription csub;
final Object guard;
volatile int wip;
@SuppressWarnings("rawtypes")
static final AtomicIntegerFieldUpdater WIP_UPDATER
= AtomicIntegerFieldUpdater.newUpdater(SourceSubscriber.class, "wip");
/** Guarded by guard. */
int active;
/** Guarded by guard. */
final Queue> queue;
public SourceSubscriber(int maxConcurrency, Subscriber s, CompositeSubscription csub) {
super(s);
this.maxConcurrency = maxConcurrency;
this.s = s;
this.csub = csub;
this.guard = new Object();
this.queue = new LinkedList>();
this.wip = 1;
}
@Override
public void onNext(Observable extends T> t) {
synchronized (guard) {
queue.add(t);
}
subscribeNext();
}
void subscribeNext() {
Observable extends T> t;
synchronized (guard) {
t = queue.peek();
if (t == null || active >= maxConcurrency) {
return;
}
active++;
queue.poll();
}
Subscriber itemSub = new Subscriber() {
boolean once = true;
@Override
public void onNext(T t) {
s.onNext(t);
}
@Override
public void onError(Throwable e) {
SourceSubscriber.this.onError(e);
}
@Override
public void onCompleted() {
if (once) {
once = false;
synchronized (guard) {
active--;
}
csub.remove(this);
subscribeNext();
SourceSubscriber.this.onCompleted();
}
}
};
csub.add(itemSub);
WIP_UPDATER.incrementAndGet(this);
t.unsafeSubscribe(itemSub);
}
@Override
public void onError(Throwable e) {
s.onError(e);
unsubscribe();
}
@Override
public void onCompleted() {
if (WIP_UPDATER.decrementAndGet(this) == 0) {
s.onCompleted();
}
}
}
}