1

I am running RxJava and creating a subject to use onNext() method to produce data. I am using Spring.

This is my setup:

@Component
public class SubjectObserver {
    private SerializedSubject<SomeObj, SomeObj> safeSource;
    public SubjectObserver() {
       safeSource = PublishSubject.<SomeObj>create().toSerialized();
       **safeSource.subscribeOn(<my taskthreadExecutor>);**
       **safeSource.observeOn(<my taskthreadExecutor>);** 
       safeSource.subscribe(new Subscriber<AsyncRemoteRequest>() {
          @Override
          public void onNext(AsyncRemoteRequest asyncRemoteRequest) {
            LOGGER.debug("{} invoked.", Thread.currentThread().getName());
            doSomething();
          }
      }
    }
    public void publish(SomeObj myObj) {
        safeSource.onNext(myObj);
    }
}

The way new data is generated on the RxJava stream is by @Autowire private SubjectObserver subjectObserver and then calling subjectObserver.publish(newDataObjGenerated)

No matter what I specify for subscribeOn() & observeOn():

  • Schedulers.io()
  • Schedulers.computation()
  • my threads
  • Schedulers.newThread

The onNext() and the actual work inside it is done on the same thread that actually calls the onNext() on the subject to generate/produce data.

Is this correct? If so, what am I missing? I was expecting the doSomething() to be done on a different thread.

Update

In my calling class, if I change the way I am invoking the publish method, then of course a new thread is allocated for the subscriber to run on.

taskExecutor.execute(() -> subjectObserver.publish(newlyGeneratedObj));

Thanks,

I'm a frog dragon
  • 7,865
  • 7
  • 46
  • 49
ameet chaubal
  • 1,440
  • 16
  • 37
  • What you are experiencing is intended by design. If you call onNext from threadX, the next operator in the chain will be invoked by the same thread. subscribeOn will not help you, because you can not manipulate from where the onNext will be invoked, you only can maintain the contract by using toSerialized. I would suggest, that you put through a "event"-instance with onNext-operator, then use observeOn and after changing the thread you could use flatMap to invoke doSomething(). In the subscribe-callback you would set your UI or whatever you want to do with the result. – Sergej Isbrecht Oct 25 '16 at 18:44

1 Answers1

9

Each operator on Observable/Subject return a new instance with the extra behavior, however, your code just applies the subscribeOn and observeOn then throws away whatever they produced and subscribes to the raw Subject. You should chain the method calls and then subscribe:

safeSource = PublishSubject.<AsyncRemoteRequest>create().toSerialized();

safeSource
.subscribeOn(<my taskthreadExecutor>)
.observeOn(<my taskthreadExecutor>)
.subscribe(new Subscriber<AsyncRemoteRequest>() {
     @Override
     public void onNext(AsyncRemoteRequest asyncRemoteRequest) {
         LOGGER.debug("{} invoked.", Thread.currentThread().getName());
         doSomething();
     }
});

Note that subscribeOn has no practical effect on a PublishSubject because there is no subscription side-effect happening in its subscribe() method.

akarnokd
  • 69,132
  • 14
  • 157
  • 192