@Override public void onComplete() { if (!terminalEvent.compareAndSet(null, ExceptionHelper.TERMINATED)) { return; } Object o = NotificationLite.complete(); for (BehaviorDisposable<T> bs : terminate(o)) { bs.emitNext(o, index); // relaxed read okay since this is the only mutator thread } }
void emitFirst() { if (cancelled) { return; } Object o; synchronized (this) { if (cancelled) { return; } if (next) { return; } BehaviorSubject<T> s = state; Lock lock = s.readLock; lock.lock(); index = s.index; o = s.value.get(); lock.unlock(); emitting = o != null; next = true; } if (o != null) { if (test(o)) { return; } emitLoop(); } }
void emitNext(Object value, long stateIndex) { if (cancelled) { return; } if (!fastPath) { synchronized (this) { if (cancelled) { return; } if (index == stateIndex) { return; } if (emitting) { AppendOnlyLinkedArrayList<Object> q = queue; if (q == null) { q = new AppendOnlyLinkedArrayList<Object>(4); queue = q; } q.add(value); return; } next = true; } fastPath = true; } test(value); }
@Override protected void subscribeActual(Observer<? super T> observer) { BehaviorDisposable<T> bs = new BehaviorDisposable<T>(observer, this); observer.onSubscribe(bs); if (add(bs)) { if (bs.cancelled) { remove(bs); } else { bs.emitFirst(); } } else { Throwable ex = terminalEvent.get(); if (ex == ExceptionHelper.TERMINATED) { observer.onComplete(); } else { observer.onError(ex); } } }
void emitNext(Object value, long stateIndex) { if (cancelled) { return; } if (!fastPath) { synchronized (this) { if (cancelled) { return; } if (index == stateIndex) { return; } if (emitting) { AppendOnlyLinkedArrayList<Object> q = queue; if (q == null) { q = new AppendOnlyLinkedArrayList<Object>(4); queue = q; } q.add(value); return; } next = true; } fastPath = true; } test(value); }
@Test public void emitNextDisposeRace() { for (int i = 0; i < TestHelper.RACE_LONG_LOOPS; i++) { BehaviorSubject<Integer> bs = BehaviorSubject.create(); bs.onNext(1); TestObserver<Integer> to = new TestObserver<Integer>(); final BehaviorDisposable<Integer> bd = new BehaviorDisposable<Integer>(to, bs); to.onSubscribe(bd); Runnable r1 = new Runnable() { @Override public void run() { bd.emitNext(2, 0); } }; Runnable r2 = new Runnable() { @Override public void run() { bd.dispose(); } }; TestHelper.race(r1, r2); } }
void emitFirst() { if (cancelled) { return; } Object o; synchronized (this) { if (cancelled) { return; } if (next) { return; } BehaviorSubject<T> s = state; Lock lock = s.readLock; lock.lock(); index = s.index; o = s.value.get(); lock.unlock(); emitting = o != null; next = true; } if (o != null) { if (test(o)) { return; } emitLoop(); } }
@Override public void onError(Throwable t) { ObjectHelper.requireNonNull(t, "onError called with null. Null values are generally not allowed in 2.x operators and sources."); if (!terminalEvent.compareAndSet(null, t)) { RxJavaPlugins.onError(t); return; } Object o = NotificationLite.error(t); for (BehaviorDisposable<T> bs : terminate(o)) { bs.emitNext(o, index); } }
@Override public void onNext(T t) { ObjectHelper.requireNonNull(t, "onNext called with null. Null values are generally not allowed in 2.x operators and sources."); if (terminalEvent.get() != null) { return; } Object o = NotificationLite.next(t); setCurrent(o); for (BehaviorDisposable<T> bs : subscribers.get()) { bs.emitNext(o, index); } }
@Test public void emitFirstDisposeRace() { for (int i = 0; i < TestHelper.RACE_LONG_LOOPS; i++) { BehaviorSubject<Integer> bs = BehaviorSubject.create(); bs.onNext(1); TestObserver<Integer> to = new TestObserver<Integer>(); final BehaviorDisposable<Integer> bd = new BehaviorDisposable<Integer>(to, bs); to.onSubscribe(bd); Runnable r1 = new Runnable() { @Override public void run() { bd.emitFirst(); } }; Runnable r2 = new Runnable() { @Override public void run() { bd.dispose(); } }; TestHelper.race(r1, r2); } }
@Override protected void subscribeActual(Observer<? super T> observer) { BehaviorDisposable<T> bs = new BehaviorDisposable<T>(observer, this); observer.onSubscribe(bs); if (add(bs)) { if (bs.cancelled) { remove(bs); } else { bs.emitFirst(); } } else { Throwable ex = terminalEvent.get(); if (ex == ExceptionHelper.TERMINATED) { observer.onComplete(); } else { observer.onError(ex); } } }
@Test public void behaviorDisposableDisposeState() { BehaviorSubject<Integer> bs = BehaviorSubject.create(); bs.onNext(1); TestObserver<Integer> to = new TestObserver<Integer>(); BehaviorDisposable<Integer> bd = new BehaviorDisposable<Integer>(to, bs); to.onSubscribe(bd); assertFalse(bd.isDisposed()); bd.dispose(); assertTrue(bd.isDisposed()); bd.dispose(); assertTrue(bd.isDisposed()); assertTrue(bd.test(2)); bd.emitFirst(); to.assertEmpty(); bd.emitNext(2, 0); }
@Test public void emittingEmitNext() { BehaviorSubject<Integer> bs = BehaviorSubject.create(); bs.onNext(1); TestObserver<Integer> to = new TestObserver<Integer>(); final BehaviorDisposable<Integer> bd = new BehaviorDisposable<Integer>(to, bs); to.onSubscribe(bd); bd.emitting = true; bd.emitNext(2, 1); bd.emitNext(3, 2); assertNotNull(bd.queue); } }
@Override public void onError(Throwable t) { ObjectHelper.requireNonNull(t, "onError called with null. Null values are generally not allowed in 2.x operators and sources."); if (!terminalEvent.compareAndSet(null, t)) { RxJavaPlugins.onError(t); return; } Object o = NotificationLite.error(t); for (BehaviorDisposable<T> bs : terminate(o)) { bs.emitNext(o, index); } }
@Override public void onNext(T t) { ObjectHelper.requireNonNull(t, "onNext called with null. Null values are generally not allowed in 2.x operators and sources."); if (terminalEvent.get() != null) { return; } Object o = NotificationLite.next(t); setCurrent(o); for (BehaviorDisposable<T> bs : subscribers.get()) { bs.emitNext(o, index); } }
@Override public void run() { bd.dispose(); } };
@Override public void onComplete() { if (!terminalEvent.compareAndSet(null, ExceptionHelper.TERMINATED)) { return; } Object o = NotificationLite.complete(); for (BehaviorDisposable<T> bs : terminate(o)) { bs.emitNext(o, index); // relaxed read okay since this is the only mutator thread } }
@Override public void run() { bd.emitNext(2, 0); } };
@Override public void run() { bd.dispose(); } };
@Override public void run() { bd.emitFirst(); } };