@Override public Disposable schedule(Runnable task) { if (tasksRemaining.decrementAndGet() < 0) throw new RejectedExecutionException("BoundedWorker schedule: no more tasks"); return actual.schedule(task); } }
void requestUpstream(final long n, final Subscription s) { if (!requestOnSeparateThread || Thread.currentThread() == THREAD.get(this)) { s.request(n); } else { try { worker.schedule(() -> s.request(n)); } catch (RejectedExecutionException ree) { if(!worker.isDisposed()) { //FIXME should not throw but if we implement strict // serialization like in StrictSubscriber, onNext will carry an // extra cost throw Operators.onRejectedExecution(ree, this, null, null, actual.currentContext()); } } } }
void trySchedule(long n, Subscription s) { if (Thread.currentThread() == THREAD.get(this)) { s.request(n); } else { try { worker.schedule(() -> s.request(n)); } catch (RejectedExecutionException ree) { if (!worker.isDisposed()) { actual.onError(Operators.onRejectedExecution(ree, this, null, null, actual.currentContext())); } } } }
@Test(timeout = 5000) public void singleSchedulerThreadCheck() throws Exception{ Scheduler s = Schedulers.newSingle("work"); try { Scheduler.Worker w = s.createWorker(); Thread currentThread = Thread.currentThread(); AtomicReference<Thread> taskThread = new AtomicReference<>(currentThread); CountDownLatch latch = new CountDownLatch(1); w.schedule(() -> { taskThread.set(Thread.currentThread()); latch.countDown(); }); latch.await(); assertThat(taskThread.get()).isNotEqualTo(currentThread); } finally { s.dispose(); } }
@Test(timeout = 5000) public void parallelSchedulerThreadCheck() throws Exception{ Scheduler s = Schedulers.newParallel("work", 2); try { Scheduler.Worker w = s.createWorker(); Thread currentThread = Thread.currentThread(); AtomicReference<Thread> taskThread = new AtomicReference<>(currentThread); CountDownLatch latch = new CountDownLatch(1); w.schedule(() -> { taskThread.set(Thread.currentThread()); latch.countDown(); }); latch.await(); assertThat(taskThread.get()).isNotEqualTo(currentThread); } finally { s.dispose(); } }
@Test public void scheduledDoesntReject() { Scheduler s = scheduler(); assertThat(s.schedule(() -> {}, 100, TimeUnit.MILLISECONDS)) .describedAs("direct delayed scheduling") .isNotNull(); assertThat(s.schedulePeriodically(() -> {}, 100, 100, TimeUnit.MILLISECONDS)) .describedAs("direct periodic scheduling") .isNotNull(); Scheduler.Worker w = s.createWorker(); assertThat(w.schedule(() -> {}, 100, TimeUnit.MILLISECONDS)) .describedAs("worker delayed scheduling") .isNotNull(); assertThat(w.schedulePeriodically(() -> {}, 100, 100, TimeUnit.MILLISECONDS)) .describedAs("worker periodic scheduling") .isNotNull(); }
@Test public void scheduledDoesntReject() { Scheduler s = Schedulers.fromExecutorService(Executors.newSingleThreadScheduledExecutor()); assertThat(s.schedule(() -> {}, 100, TimeUnit.MILLISECONDS)) .describedAs("direct delayed scheduling") .isNotNull(); assertThat(s.schedulePeriodically(() -> {}, 100, 100, TimeUnit.MILLISECONDS)) .describedAs("direct periodic scheduling") .isNotNull(); Worker w = s.createWorker(); assertThat(w.schedule(() -> {}, 100, TimeUnit.MILLISECONDS)) .describedAs("worker delayed scheduling") .isNotNull(); assertThat(w.schedulePeriodically(() -> {}, 100, 100, TimeUnit.MILLISECONDS)) .describedAs("worker periodic scheduling") .isNotNull(); }
@Test public void scheduledDoesntReject() { Scheduler s = scheduler(); assertThat(s.schedule(() -> {}, 100, TimeUnit.MILLISECONDS)) .describedAs("direct delayed scheduling") .isNotNull(); assertThat(s.schedulePeriodically(() -> {}, 100, 100, TimeUnit.MILLISECONDS)) .describedAs("direct periodic scheduling") .isNotNull(); Scheduler.Worker w = s.createWorker(); assertThat(w.schedule(() -> {}, 100, TimeUnit.MILLISECONDS)) .describedAs("worker delayed scheduling") .isNotNull(); assertThat(w.schedulePeriodically(() -> {}, 100, 100, TimeUnit.MILLISECONDS)) .describedAs("worker periodic scheduling") .isNotNull(); }
@Test public void singleSchedulerPipelining() throws Exception { Scheduler serviceRB = Schedulers.newSingle("rb", true); Scheduler.Worker dispatcher = serviceRB.createWorker(); try { Thread t1 = Thread.currentThread(); Thread[] t2 = { null }; CountDownLatch cdl = new CountDownLatch(1); dispatcher.schedule(() -> { t2[0] = Thread.currentThread(); cdl.countDown(); }); if (!cdl.await(5, TimeUnit.SECONDS)) { Assert.fail("single timed out"); } Assert.assertNotSame(t1, t2[0]); } finally { dispatcher.dispose(); } }
@Override public void onError(final Throwable t) { if (done) { Operators.onErrorDropped(t, currentContext()); return; } done = true; //if no currently delayed onNext (eg. empty source), // we can immediately error if (DELAYED.compareAndSet(this, 0, -1)) { actual.onError(t); } else { w.schedule(new OnError(t), delay, timeUnit); } }
void trySchedule( @Nullable Subscription subscription, @Nullable Throwable suppressed, @Nullable Object dataSignal) { if (WIP.getAndIncrement(this) != 0) { return; } try { worker.schedule(this); } catch (RejectedExecutionException ree) { Operators.onDiscardQueueWithClear(queue, actual.currentContext(), null); actual.onError(Operators.onRejectedExecution(ree, subscription, suppressed, dataSignal, actual.currentContext())); } }
@Override public void onComplete() { if (done) { return; } done = true; //if no currently delayed onNext (eg. empty source), // we can immediately complete if (DELAYED.compareAndSet(this, 0, -1)) { actual.onComplete(); } else { w.schedule(new OnComplete(), delay, timeUnit); } }
@Override public void subscribe(CoreSubscriber<? super T> actual) { Scheduler.Worker worker = scheduler.createWorker(); SubscribeOnSubscriber<T> parent = new SubscribeOnSubscriber<>(source, actual, worker); actual.onSubscribe(parent); try { worker.schedule(parent); } catch (RejectedExecutionException ree) { if (parent.s != Operators.cancelledSubscription()) { actual.onError(Operators.onRejectedExecution(ree, parent, null, null, actual.currentContext())); } } }
void trySchedule( @Nullable Subscription subscription, @Nullable Throwable suppressed, @Nullable Object dataSignal) { if (WIP.getAndIncrement(this) != 0) { return; } try { worker.schedule(this); } catch (RejectedExecutionException ree) { Operators.onDiscardQueueWithClear(queue, actual.currentContext(), null); actual.onError(Operators.onRejectedExecution(ree, subscription, suppressed, dataSignal, actual.currentContext())); } }
@Override public Disposable schedule(Runnable task) { return main.schedule(task); }
@Override public void execute(Runnable command) { main.schedule(command); }
@Override public Disposable schedule(Runnable task, long delay, TimeUnit unit) { return main.schedule(task, delay, unit); }
@Test public void recursiveParallelCall() throws Exception { Scheduler s = Schedulers.newParallel("work", 4); try { Scheduler.Worker w = s.createWorker(); CountDownLatch latch = new CountDownLatch(2); w.schedule(() -> recursiveCall(w, latch, 0)); latch.await(); } finally { s.dispose(); } }
@Override public void onNext(final T t) { if (done || delayed < 0) { Operators.onNextDropped(t, currentContext()); return; } //keep track of the number of delayed onNext so that //we can also delay onError/onComplete when an onNext //is "in flight" DELAYED.incrementAndGet(this); w.schedule(() -> delayedNext(t), delay, timeUnit); }
void recursiveCall(Scheduler.Worker w, CountDownLatch latch, int data){ if (data < 2) { latch.countDown(); w.schedule(() -> recursiveCall(w, latch,data + 1)); } }