当使用SingleScheduler从多个线程调用时,RxJava2 PublishSubject订阅者无法接收项目

时间:2017-03-24 18:13:00

标签: java multithreading kotlin rx-java2

我有以下单元测试,其中我尝试从不同的线程发送10 String并测试我从单个线程接收这些String。我的问题是这个测试襟翼。有时它会成功,但有时我只收到89个项目,然后测试会挂起,直到锁定超时。我是以错误的方式使用SingleScheduler吗?我错过了别的什么吗?

val consumerCallerThreadNames = mutableSetOf<String>()
val messageCount = AtomicInteger(0)

val latch = CountDownLatch(MESSAGE_COUNT)

@Test
fun someTest() {
    val msg = "foo"

    val subject = PublishSubject.create<String>()
    subject
            .observeOn(SingleScheduler())
            .subscribe({ message ->
                consumerCallerThreadNames.add(Thread.currentThread().name)
                messageCount.incrementAndGet()
                latch.countDown()
            }, Throwable::printStackTrace)

    1.rangeTo(MESSAGE_COUNT).forEach {
        Thread({
            try {
                subject.onNext(msg)
            } catch (t: Throwable) {
                t.printStackTrace()
            }
        }).start()
    }
    latch.await(10, SECONDS)

    assertThat(consumerCallerThreadNames).hasSize(1)
    assertThat(messageCount.get()).isEqualTo(MESSAGE_COUNT)
}

companion object {
    val MESSAGE_COUNT = 10
}

如果我重写这个以使用单线程ExecutorService,测试不再fla,所以问题是Rx或我对Rx缺乏了解。

1 个答案:

答案 0 :(得分:4)

RxJava要求对on*的调用不会同时发生。这意味着您的代码不是线程安全的。

由于只有主题本身以并发方式使用,因此应该通过使用Subject<T>.toSerialized()方法序列化(本质上是Java的“同步”)主题本身来修复它。

val subject = PublishSubject.create<String>()变为val subject = PublishSubject.create<String>().toSerialized()