RxJava Thread.sleep()中断了异常

时间:2015-11-26 23:34:04

标签: java rx-java

我正在使用RxJava(自定义缓存可观察)工作,我发现了以下问题。

示例很简单:创建可观察的订阅者,并立即取消订阅。

public static void main(String[] args) {
Observable<Long> origin = Observable.create(new Observable.OnSubscribe<Long>() {
    @Override public void call(Subscriber<? super Long> subscriber) {
        try {
            System.out.println("Starting... > " + Thread.currentThread().getName());
            Thread.sleep(3000);
            subscriber.onNext(System.currentTimeMillis());
            Thread.sleep(200);
            subscriber.onCompleted();
            System.out.println("Complete...");
        } catch(Exception e) {
            e.printStackTrace();
            subscriber.onError(e);
        }
    }
});

Subscription sub1 = origin.subscribeOn(Schedulers.newThread()).subscribe(new Observer<Long>() {
    @Override public void onCompleted() { }
    @Override public void onError(Throwable e) { e.printStackTrace();  }
    @Override public void onNext(Long value) {
        System.out.println("onNext() > " + value);
    }
});

try {
    sub1.unsubscribe();
} catch (Exception e) {
    e.printStackTrace();
}

try {
    System.in.read(); // wait for user input to finish
} catch (IOException e) {
    e.printStackTrace();
}

}

如果你多次运行以下程序,你应该得到以下异常(尝试直到你得到异常)

java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at org.skendel.Program$1.call(Program.java:23)
    at org.skendel.Program$1.call(Program.java:19)
    at rx.Observable.unsafeSubscribe(Observable.java:7710)
    at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at org.skendel.Program$1.call(Program.java:23)
    at org.skendel.Program$1.call(Program.java:19)
    at rx.Observable.unsafeSubscribe(Observable.java:7710)
    at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

我的问题是:为什么会发生此异常(有时)? 即使创建了.cache()observable也会发生这种情况。

异常与Observable.OnSubscribe()的实现中的第一个Thread.sleep()调用相关联。

3 个答案:

答案 0 :(得分:3)

您正在尝试取消订阅当前正在运行的活动(Thread.sleep())。你的图书馆显然已经检测到这一点,并试图唤醒你的事件以阻止它。无论如何,您不应该依赖代码中的Sleep()。总有一种更好,更正确的方式。另外,作为规则的拇指,事件应该始终尽可能快。

如果您足够快地取消订阅,则不会发生异常:您的活动没有解雇,也没有睡觉,因此也不例外。

尝试延迟取消订阅一秒钟,它应该一直开启,并且一直创建一个例外。

答案 1 :(得分:1)

启动新线程可能需要一些时间(甚至1毫秒),这使主线程有足够的时间来取消订阅,从而取消subscribeOn计划的任务。其他时候,线程旋转得如此之快,以至于它开始运行OnSubscribe代码,该代码现在被取消订阅调用中断。

正如其他人提到的那样,你应该尽量避免代码中的睡眠,而是使用delay设置序列,或者在一段时间后使用Scheduler.Worker.schedule()来触发操作。

答案 2 :(得分:0)

我的假设是异常不会发生,只有当主线程在Observable进入睡眠状态之前到达sub1.unsubscribe();行时,因为它是unsubscribe调用,它会以极大的方式唤醒Observable - 因为它删除订阅的线程origin

预计会出现此异常,因此请单独处理,而不是onError()方法。