我正在使用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()调用相关联。
答案 0 :(得分:3)
您正在尝试取消订阅当前正在运行的活动(Thread.sleep()
)。你的图书馆显然已经检测到这一点,并试图唤醒你的事件以阻止它。无论如何,您不应该依赖代码中的Sleep()
。总有一种更好,更正确的方式。另外,作为规则的拇指,事件应该始终尽可能快。
如果您足够快地取消订阅,则不会发生异常:您的活动没有解雇,也没有睡觉,因此也不例外。
尝试延迟取消订阅一秒钟,它应该一直开启,并且一直创建一个例外。
答案 1 :(得分:1)
启动新线程可能需要一些时间(甚至1毫秒),这使主线程有足够的时间来取消订阅,从而取消subscribeOn
计划的任务。其他时候,线程旋转得如此之快,以至于它开始运行OnSubscribe
代码,该代码现在被取消订阅调用中断。
正如其他人提到的那样,你应该尽量避免代码中的睡眠,而是使用delay
设置序列,或者在一段时间后使用Scheduler.Worker.schedule()
来触发操作。
答案 2 :(得分:0)
我的假设是异常不会发生,只有当主线程在Observable进入睡眠状态之前到达sub1.unsubscribe();
行时,因为它是unsubscribe
调用,它会以极大的方式唤醒Observable - 因为它删除订阅的线程origin
。
预计会出现此异常,因此请单独处理,而不是onError()方法。