toBlockingFirst()方法可靠性问询:dispose时是否触发InterruptedException崩溃
blockingFirst() Reliable? Will It Throw InterruptedException on Dispose? Great question—let's unpack this step by step, including your specific code scenario.
Core Questions Answered
1. Is blockingFirst() reliable?
Yes, but only if you use it appropriately. This blocking method will:
- Wait synchronously until the source Observable emits its first item, then return that item immediately.
- Throw
NoSuchElementExceptionif the Observable completes without emitting any items. - Propagate any errors emitted by the source Observable.
When the associated Disposable is disposed, blockingFirst() will terminate immediately:
- If no item was emitted yet, it throws
IllegalStateException(indicating the sequence was cancelled). - If an item was already emitted, it returns that item normally.
2. Will calling dispose() trigger an InterruptedException and crash?
No, not by default. InterruptedException is thrown only when the thread executing blockingFirst() is explicitly interrupted (e.g., via Thread.currentThread().interrupt()). Calling dispose() on the subscription does not directly interrupt the thread—it simply cancels the Observable sequence, which causes blockingFirst() to terminate with an IllegalStateException (if no item was emitted) rather than an interrupt.
That said, if your code manually interrupts the thread running blockingFirst(), you will need to handle InterruptedException to avoid crashes.
Issues with Your Example Code
Your current code uses blockingFirst() inside a flatMap operator, which is a problematic practice:
.flatMap{ host -> val count = userRepository.getUsers(PrefProvider.currentTourCode) .map { it.size } .blockingFirst() if (count>2) { callSomething() } else { callElse() } }
- Blocking inside
flatMap(which runs on a RxJava scheduler thread) will block that thread, potentially starving the scheduler's thread pool, causing performance issues, or even deadlocks. - This defeats the purpose of RxJava's reactive, non-blocking paradigm.
Recommended Reactive Alternative
Rewrite your logic to use RxJava's reactive operators instead of blocking:
.flatMap{ host -> userRepository.getUsers(PrefProvider.currentTourCode) .map { it.size } .flatMap { count -> if (count > 2) { // Assume callSomething() returns an Observable/Maybe/Single callSomething() } else { // Assume callElse() returns an Observable/Maybe/Single callElse() } } }
If callSomething() and callElse() are not reactive (i.e., they return void or a non-Rx type), use doOnNext to handle the side effects while keeping the stream non-blocking:
.flatMap{ host -> userRepository.getUsers(PrefProvider.currentTourCode) .map { it.size } .doOnNext { count -> if (count > 2) { callSomething() } else { callElse() } } }
Final Takeaways
blockingFirst()is reliable for specific use cases (e.g., integrating reactive code with legacy synchronous code), but avoid using it within RxJava's operator chain.- Calling
dispose()won't triggerInterruptedException, but you should handleIllegalStateExceptionandNoSuchElementExceptionto prevent unexpected crashes. - Always prefer reactive operators over blocking calls to maintain RxJava's performance and non-blocking benefits.
内容的提问来源于stack exchange,提问作者Serg Burlaka

