Thread execution of value emitting code and value receiving code in RxJava - java

I have following code:
private static void log(Object msg) {
System.out.println(
Thread.currentThread().getName() +
": " + msg);
}
Observable<Integer> naturalNumbers = Observable.create(emitter -> {
log("Invoked"); // on main thread
Runnable r = () -> {
log("Invoked on another thread");
int i = 0;
while(!emitter.isDisposed()) {
log("Emitting "+ i);
emitter.onNext(i);
i += 1;
}
};
new Thread(r).start();
});
Disposable disposable = naturalNumbers.subscribe(i -> log("Received "+i));
So here we have 2 important lambda expressions. First is the one we pass to Observable.create, second is the callback one we pass to Observable.subscribe(). In first lambda, we create a new thread and then emit values on that thread. In second lambda, we have the code to receive those values emitted in first lambda code. I observe that both code are executed on same thread.
Thread-0: Invoked on another thread
Thread-0: Emitting 0
Thread-0: Received 0
Thread-0: Emitting 1
Thread-0: Received 1
Thread-0: Emitting 2
Thread-0: Received 2
Why is it so? Does RxJava by default run code emitting values(observable) and the code receiving values(observer) on same thread?

Let's see, what happens, if you use a Thread to execute a runnable:
Test
#Test
void threadTest() throws Exception {
log("main");
CountDownLatch countDownLatch = new CountDownLatch(1);
new Thread(
() -> {
log("thread");
countDownLatch.countDown();
})
.start();
countDownLatch.await();
}
Output
main: main
Thread-0: thread
It seems, that the main entry point is called from main thread and the newly created Thread is called Thread-0.
Why is it so? Does RxJava by default run code emitting values(observable) and the code receiving values(observer) on same thread?
By default RxJava is single-threaded. Therefore the the producer, if not definied differently by observeOn, subscribeOn or different threading layout, will emit values on the consumer (subsriber)-thread. This is because RxJava runs everything on the subscribing stack by default.
Example 2
#Test
void fdskfkjsj() throws Exception {
log("main");
Observable<Integer> naturalNumbers =
Observable.create(
emitter -> {
log("Invoked"); // on main thread
Runnable r =
() -> {
log("Invoked on another thread");
int i = 0;
while (!emitter.isDisposed()) {
log("Emitting " + i);
emitter.onNext(i);
i += 1;
}
};
new Thread(r).start();
});
Disposable disposable = naturalNumbers.subscribe(i -> log("Received " + i));
Thread.sleep(100);
}
Output2
main: main
main: Invoked
Thread-0: Invoked on another thread
Thread-0: Emitting 0
Thread-0: Received 0
Thread-0: Emitting 1
In your example it is apparent, that the main method is called from the main thread. Furthermore the subscribeActual call is also run on the calling-thread (main). But the Observable#create lambda calls onNext from the newly created thread Thread-0. The value is pushed to the subscriber from the calling thread. In this case, the calling thread is Thread-0, because it calls onNext on the downstream subscriber.
How to separate producer from consumer?
Use observeOn/ subscribeOn operators in order to handle concurrency in RxJava.
Should I use low-level Thread constructs แบith RxJava?
No you should not use new Thread in order to seperate the producer from the consumer. It is quite easy to break the contract, that onNext can not be called concurrently (interleaving) and therefore breaking the contract. This is why RxJava provides a construct called Scheduler with Workers in order to mitigate such mistakes.
Note:
I think this article describes it quite well: http://introtorx.com/Content/v1.0.10621.0/15_SchedulingAndThreading.html . Please note this is Rx.NET, but the principle is quite the same. If you want to read about concurrency with RxJava you could also look into Davids Blog (https://akarnokd.blogspot.com/2015/05/schedulers-part-1.html) or read this Book (Reactive Programming with RxJava https://www.oreilly.com/library/view/reactive-programming-with/9781491931646/)

Related

Thread used for Java CompletableFuture composition?

I'm starting to be comfortable with Java CompletableFuture composition, having worked with JavaScript promises. Basically the composition just scheduled the chained commands on the indicated executor. But I'm unsure of which thread is running when the composition is performed.
Let's say I have two executors, executor1 and executor2; for simplicity let's say they are separate thread pools. I schedule a CompletableFuture (to use a very loose description):
CompletableFuture<Foo> futureFoo = CompletableFuture.supplyAsync(this::getFoo, executor1);
Then when that is done I transform the Foo to Bar using the second executor:
CompletableFuture<Bar> futureBar .thenApplyAsync(this::fooToBar, executor2);
I understand that getFoo() will be called from a thread in the executor1 thread pool. I understand that fooToBar() will be called from a thread in the executor2 thread pool.
But what thread is used for the actual composition, i.e. after getFoo() finishes and futureFoo() is complete; but before the fooToBar() command gets scheduled on executor2? In other words, what thread actually runs the code to schedule the second command on the second executor?
Is the scheduling performed as part of the same thread in executor1 that called getFoo()? If so, would this completable future composition be equivalent to my simply scheduling fooToBar() manually myself in the first command in the executor1 task?
This is intentionally unspecified. In practice, it will be handled by the same code that also handles the chained operations when the variants without the Async suffix are invoked and exhibits similar behavior.
So when we use the following test code
CompletableFuture.supplyAsync(() -> {
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
return "";
}, r -> new Thread(r, "A").start())
.thenAcceptAsync(s -> {}, r -> {
System.out.println("scheduled by " + Thread.currentThread());
new Thread(r, "B").start();
});
it will likely print
scheduled by Thread[A,5,main]
as the thread that completed the previous stage was used to schedule the depending action.
However when we use
CompletableFuture<String> first = CompletableFuture.supplyAsync(() -> "",
r -> new Thread(r, "A").start());
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
first.thenAcceptAsync(s -> {}, r -> {
System.out.println("scheduled by " + Thread.currentThread());
new Thread(r, "B").start();
});
it will likely print
scheduled by Thread[main,5,main]
as by the time the main thread invokes thenAcceptAsync, the first future is already completed and the main thread will schedule the action itself.
But that is not the end of the story. When we use
CompletableFuture<String> first = CompletableFuture.supplyAsync(() -> {
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(5));
return "";
}, r -> new Thread(r, "A").start());
Set<String> s = ConcurrentHashMap.newKeySet();
Runnable submitter = () -> {
String n = Thread.currentThread().getName();
do {
for(int i = 0; i < 1000; i++)
first.thenAcceptAsync(x -> s.add(n+" "+Thread.currentThread().getName()),
Runnable::run);
} while(!first.isDone());
};
Thread b = new Thread(submitter, "B");
Thread c = new Thread(submitter, "C");
b.start();
c.start();
b.join();
c.join();
System.out.println(s);
It may not only print the combinations B A and C A from the first scenario and B B and C C from the second. On my machine it reproducibly also prints the combinations B C and C B indicating that an action passed to thenAcceptAsync by one thread got submitted to the executor by the other thread calling thenAcceptAsync with a different action at the same time.
This is matching the scenarios for the thread evaluating the function passed to thenApply (without the Async) described in this answer. As said at the beginning, that was what I expected as both things are likely handled by the same code. But unlike the thread evaluating the function passed to thenApply, the thread invoking the execute method on the Executor is not even mentioned in the documentation. So in theory, another implementation could use an entirely different thread not calling a method on the future nor completing it.
At the end is a simple program that does like your code snippet and allows you to play with it.
The output confirms that the executor you supply is called to complete (unless you explicitly call complete early enough - which would happen in the calling thread of complete) when the condition it is waiting on is ready - the get() on a Future blocks until the Future is finished.
Supply an arg - there's an executor 1 and executor 2, supply no args there's just one executor. The output is either (same executor - things a run as separate tasks in the same executor sequentially) -
In thread Thread[main,5,main] - getFoo
In thread Thread[main,5,main] - getFooToBar
In thread Thread[pool-1-thread-1,5,main] - Supplying Foo
In thread Thread[pool-1-thread-1,5,main] - fooToBar
In thread Thread[main,5,main] - Completed
OR (two executors - things again run sequentially but using different executors) -
In thread Thread[main,5,main] - getFoo
In thread Thread[main,5,main] - getFooToBar
In thread Thread[pool-1-thread-1,5,main] - Supplying Foo
In thread Thread[pool-2-thread-1,5,main] - fooToBar
In thread Thread[main,5,main] - Completed
Remember: the code with the executors (in this example can start immediately in another thread .. the getFoo was called prior to even getting to setting up the FooToBar).
Code follows -
package your.test;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.function.Supplier;
public class TestCompletableFuture {
private static void dumpWhichThread(final String msg) {
System.err.println("In thread " + Thread.currentThread().toString() + " - " + msg);
}
private static final class Foo {
final int i;
Foo(int i) {
this.i = i;
}
};
public static Supplier<Foo> getFoo() {
dumpWhichThread("getFoo");
return new Supplier<Foo>() {
#Override
public Foo get() {
dumpWhichThread("Supplying Foo");
return new Foo(10);
}
};
}
private static final class Bar {
final String j;
public Bar(final String j) {
this.j = j;
}
};
public static Function<Foo, Bar> getFooToBar() {
dumpWhichThread("getFooToBar");
return new Function<Foo, Bar>() {
#Override
public Bar apply(Foo t) {
dumpWhichThread("fooToBar");
return new Bar("" + t.i);
}
};
}
public static void main(final String args[]) throws InterruptedException, ExecutionException, TimeoutException {
final TestCompletableFuture obj = new TestCompletableFuture();
obj.running(args.length == 0);
}
private String running(final boolean sameExecutor) throws InterruptedException, ExecutionException, TimeoutException {
final Executor executor1 = Executors.newSingleThreadExecutor();
final Executor executor2 = sameExecutor ? executor1 : Executors.newSingleThreadExecutor();
CompletableFuture<Foo> futureFoo = CompletableFuture.supplyAsync(getFoo(), executor1);
CompletableFuture<Bar> futureBar = futureFoo.thenApplyAsync(getFooToBar(), executor2);
try {
// Try putting a complete here before the get ..
return futureBar.get(50, TimeUnit.SECONDS).j;
}
finally {
dumpWhichThread("Completed");
}
}
}
Which thread triggers the Bar stage to progress - in the above - it's executor1. In general the thread completing the future (i.e. giving it a value) is what releases the thing depending on it. If you completed the FutureFoo immediately on the main thread - it would be the one triggering it.
SO you have to be careful with this. If you have "N" things all waiting on the future results - but use only a single threaded executor - then the first one scheduled will block that executor until it completes. You can extrapolate to M threads, N futures - it can decay into "M" locks preventing the rest of things progressing.

RxJava: subscribeOn and observeOn not working as expected

maybe I just really understand the inner workings of subscribeOn and observeOn, but I recently encountered something really odd. I was under the impression, that subscribeOn determines the Scheduler where to initially start processing (especially when we, e.g., have a lot of maps which change the stream of data) and then observeOn can be used anywhere between those maps to change Schedulers when appropriate (first do networking, then computation, finally change UI thread).
However, I noticed that when not directly chaining those calls to my Observable or Single, it won't work. Here's a minimal working Example JUnit Test:
import org.junit.Test;
import rx.Single;
import rx.schedulers.Schedulers;
public class SubscribeOnTest {
#Test public void not_working_as_expected() throws Exception {
Single<Integer> single = Single.<Integer>create(singleSubscriber -> {
System.out.println("Doing some computation on thread " + Thread.currentThread().getName());
int i = 1;
singleSubscriber.onSuccess(i);
});
single.subscribeOn(Schedulers.computation()).observeOn(Schedulers.io());
single.subscribe(integer -> {
System.out.println("Observing on thread " + Thread.currentThread().getName());
});
System.out.println("Doing test on thread " + Thread.currentThread().getName());
Thread.sleep(1000);
}
#Test public void working_as_expected() throws Exception {
Single<Integer> single = Single.<Integer>create(singleSubscriber -> {
System.out.println("Doing some computation on thread " + Thread.currentThread().getName());
int i = 1;
singleSubscriber.onSuccess(i);
}).subscribeOn(Schedulers.computation()).observeOn(Schedulers.io());
single.subscribe(integer -> {
System.out.println("Observing on thread " + Thread.currentThread().getName());
});
System.out.println("Doing test on thread " + Thread.currentThread().getName());
Thread.sleep(1000);
}
}
The test not_working_as_expected() gives me following output
Doing some computation on thread main
Observing on thread main
Doing test on thread main
whereas working_as_expected() gives me
Doing some computation on thread RxComputationScheduler-1
Doing test on thread main
Observing on thread RxIoScheduler-2
The only difference being that in the first test, after the creation of the single there is a semicolon and only then the schedulers are applied, and in the working example the method calls are directly chained to the creation of the Single. But shouldn't that be irrelevant?
All "modifications" performed by operators are immutable, meaning that they return a new stream that receives notifications in an altered manner from the previous one. Since you just called subscribeOn and observeOn operators and didn't store their result, the subscription made later is on the unaltered stream.
One side note: I didn't quite understand your definition of subscribeOn behavior. If you meant that map operators are somehow affected by it, this is not true. subscribeOn defines a Scheduler, on which the OnSubscribe function is called. In your case the function you pass to the create() method. On the other hand, observeOn defines the Scheduler on which each successive stream (streams returned by applied operators) is handling emissions coming from an upstream.
.subscribeOn(*) - returns you new instance of Observable, but in first test you just ignore that and then subscribe on original Observable, which obviously by default subscribes on default, main thread.

What thread is unSubscribeOn called? Should we call it?

What thread is unsubscribeOn defaulted to when we do not specify it but still specify the thread for subscribeOn?
Are we required to specify the thread that we want un-subscription to happen on even when it is the same thread as the one used in subscribeOn?
Or are the bottom two snippets doing the same for un-subscription?
Option 1:
mSubscription.add(myAppProvider
.getSomeData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.unsubscribeOn(Schedulers.io())
.subscribe(data -> handleData(data),
throwable -> handleError(throwable)
));
Option 2:
mSubscription.add(myAppProvider
.getSomeData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> handleData(data),
throwable -> handleError(throwable)
));
I did look at the Rx-Java docs but they only explain subscribeOn but nothing about unSubscribeOn
Those snippets have different behaviours.
In general, unsubscription travels up the operator sequence and can be initiated by any thread at all (just call subscriber.unsubscribe() from any thread). Without the presence of an unsubscribeOn operator the unsubscribe action will probably complete its action on the thread it was called from. unsubscribeOn provides finer control of the thread used for unsubscription upstream of it.
Without subscribeOn (and without observeOn), your unsubscription actions will occur on whatever thread the subscription started.
With subscribeOn, your unsubscription actions will occur on the Scheduler specified by subscribeOn.
With observeOn, your unsubscription actions will occur on the Scheduler specified by observeOn (overriding the Scheduler specified by subscribeOn).
Here is a sample. As suggested there, this is useful when the unsubscription itself involves long-running operations that you want to run on some other thread.
If you run their test code:
Observable<Object> source = Observable.using(
() -> {
System.out.println("Subscribed on " + Thread.currentThread().getId());
return Arrays.asList(1,2);
},
(ints) -> {
System.out.println("Producing on " + Thread.currentThread().getId());
return Observable.from(ints);
},
(ints) -> {
System.out.println("Unubscribed on " + Thread.currentThread().getId());
}
);
source
.unsubscribeOn(Schedulers.newThread())
.subscribe(System.out::println);
You should see their expected output:
Subscribed on 1
Producing on 1
1
2
Unubscribed on 11
If you remove that unsubscribeOn line, you'll see:
Unsubscribed on 1
What thread is unsubscribeOn defaulted to when we do not specify it
but still specify the thread for subscribeOn?
By default when neither of subscribeOn/observeOn/unsubscribeOn are
set, then unsubscribeOn (as well as others) are defaulted to the
current thread.
If we do set a thread for subscribeOn and none for
observeOn/unsubscribeOn, then unsubscribeOn will use the same thread
specified in subscribeOn.
If we call both subscribeOn and ObserveOn but not unsubscribeOn, then
unsubscribeOn will use the thread specified in observeOn.
If all three methods (subscribeOn, observeOn and unsubscribeOn) are
set, then unsubscribeOn will use the thread specified in
unsubscribeOn. In fact unsubscribeOn will happen on the thread
specified in unsubscribeOn method regardless of weather the previous
methods are set or not.
Are we required to specify the thread that we want un-subscription to
happen on even when it is the same thread as the one used in
subscribeOn?
As explained above if unsubscribeOn is not set then unsubscribeOn
happens on observeOn if it is set. If not then it happens on the
thread set by subscribeOn. Now we do not need to set a different
thread for unsubscribeOn unless you are doing some long running task
while unsubscribing. In most cases or atleast from my code, this is
true and so we do not have to set a different thread.
Here is a sample that I created that can be used to test the above in Android. Just comment out or change the threads as required to test various outcomes.
public void testRxThreads() {
createThreadObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.unsubscribeOn(Schedulers.newThread())
.subscribe(printResult());
}
private Observable<String> createThreadObservable() {
return Observable.create(subscriber -> {
subscriber.add(new Subscription() {
#Override
public void unsubscribe() {
System.out.println("UnSubscribe on Thread: "
+ Thread.currentThread().getId() + " " + Thread.currentThread().getName());
// perform unsubscription
}
#Override
public boolean isUnsubscribed() {
return false;
}
});
subscriber.setProducer(n -> {
System.out.println("Producer thread: "
+ Thread.currentThread().getId() + " " + Thread.currentThread().getName());
});
subscriber.onNext("Item 1");
subscriber.onNext("Item 2");
subscriber.onCompleted();
});
}
private Action1<String> printResult() {
return result -> {
System.out.println("Subscriber thread: "
+ Thread.currentThread().getId() + " " + Thread.currentThread().getName());
System.out.println("Result: " + result);
};
}
This produced the following result
Producer thread: 556 RxIoScheduler-2
Subscriber thread: 1 main
Result: Item 1
Subscriber thread: 1 main
Result: Item 2
UnSubscribe on Thread: 557 RxNewThreadScheduler-1
Commenting out or removing unsubscribeOn produces the following.
Subscriber thread: 1 main
Result: Item 1
Subscriber thread: 1 main
Result: Item 2
UnSubscribe on Thread: 1 main
Removing out both observeOn and unsubscribeOn calls produce the following:
Producer thread: 563 RxIoScheduler-2
Subscriber thread: 563 RxIoScheduler-2
Result: Item 1
Subscriber thread: 563 RxIoScheduler-2
Result: Item 2
UnSubscribe on Thread: 563 RxIoScheduler-2
Thanks to drhr for the initial explanation of events. That helped me research more and verify the outcomes with the sample above.

How to Concurrently Process Lines of Text with RxJava

I was wondering how I could concurrently process lines of text with RxJava. Right now, what I have is an observable from an entry set, and a subscriber that on each entry, processes the entry in the onNext call. The subscriber subscribes to the observable with this line of code
obs.observeOn(Schedulers.io()).subscribe(sub);
But when I run it, it runs as slowly as the sequential version, and seems to be processing it sequentially. How would I make this concurrent?
Your observeOn(Schedulers.io()) call means that all emissions will be observed on that one thread. You want to get them onto their own threads.
Here I use flatMap to create a new observable for each item emitted from the source. Inside the mapping function I have to defer the processing work until subscription, else the entire chain is blocked while processing completes. I also have to ensure that subscription happens on a new thread via subscribeOn.
Random r = new Random();
Observable.from(new String[]{"First", "Second", "Third", "Fourth", "Fifth"})
.flatMap(new Func1<String, Observable<String>>() {
public Observable<String> call(final String s) {
return Observable.defer(new Func0<Observable<String>>() {
public Observable<String> call() {
Thread.sleep(r.nextInt(1000));
return Observable.just(s);
}
}).subscribeOn(Schedulers.newThread());
}
})
.subscribe(new Action1<String>() {
#Override
public void call(String s) {
System.out.println("Observed " + s + " on thread " + Thread.currentThread().getId());
}
});
This gives me output like (note out-of-order and on different threads - ie, processed in parallel):
Observed Fourth on thread 17
Observed Second on thread 15
Observed Fifth on thread 18
Observed First on thread 14
Observed Third on thread 16

Java notifyAll not waking right away

So, I have the following object (simplified for sake of example):
public class SomeListener implements EventListener{
public final Object lock = new Object();
public int receivedVal;
#Override
public onDataAvailable(int val){
synchronized(lock){
System.out.println("listener received val: " + val);
receivedVal = val;
lock.notifyAll();
}
}
}
And I have this piece of code somewhere in the main thread (again, simplified):
SomeListener listener = new SomeListener();
EventGenerator generatorThread = new EventGenerator();
generatorThread.addListener(listener);
synchronize(listener.lock){
generatorThread.start();
listener.lock.wait();
System.out.println("value is: " + listener.receivedVal);
}
//some other stuff here....
Now, the EventGenerator object calls "onDataAvailable" with val = 1, then with val = 2 on a different thread. Basically, what I expect to see is:
listener received val: 1
value is: 1
listener received val: 2
However, I usually get:
listener received val: 1
listener received val: 2
value is: 2
It is as if the second call of "onDataAvailable" acquires the lock before the main thread is awaken. A simple println or a short sleep after the synchronized block of "onDataAvailable" is enough to get the expected result, but that seems like an ugly patch.
What am I doing wrong here?
Note, I do not have control on the thread that calls the listener. It's basically a thread that receives events over the network. Sometimes it will receive multiple events in the same message and will therefore call "onDataAvailable" multiple times one after the other, which leads to my problem. Other times it will receive two events in two different messages, which leaves enough time for the main thread to awake between the events.
It is as if the second call of "onDataAvailable" acquires the lock before the main thread is awaken
This is to be expected if you have multiple threads calling onDataAvailable(...). When notifyAll() is called, all of the threads that are waiting on that object are moved to the blocked queue but behind any threads already in the queue. They all have to wait to synchronize on the lock before continuing.
Other times it will receive two events in two different messages, which leaves enough time for the main thread to awake between the events.
Right, so multiple network handler threads are calling onDataAvailable(...). The 2nd one is blocked on the synchronized(lock) waiting for it. When notifyAll() is called, the other thread goes into the block queue as well but behind the other handler.
I would be surprised that you are getting that output if there is only one handler thread. In that case, the notified thread should get the synchronize lock before the single thread handler can unlock, read another message, and lock again.
What am I doing wrong here?
The problem is not with the way the threads are being handled but by the way you are handling the receivedVal. You should process the value immediately in the handling thread or you will need to put it in some sort of synchronized queue (maybe a LinkedBlockingQueue) to be printed out by the main thread in order.
If you use a BlockingQueue then the main queue just does a queue.take() which causes it to wait for a result and the handler threads just do a queue.put(...). You would not need to do the wait() or notifyAll() calls yourself.
Something like this would work:
private final BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
...
#Override
public onDataAvailable(int val){
System.out.println("listener received val: " + val);
queue.put(val);
}
...
generatorThread.addListener(listener);
generatorThread.start();
while (true) {
// this waits for the queue to get a value
int val = queue.take();
System.out.println("value is: " + val);
}

Categories