我正在使用一个代码库,其中有很多类似于以下内容的模式:
getPoJoObservableFromSomewhere() // no guarantees about the threading/scheduling here
.doOnNext(pojo -> System.out.println("got pojo: " + pojo.toString())
.doOnNext(pojo -> pojo.setName("my new pojo"))
.observeOn(newThreadScheduler)
.flatMap(pojo -> doSomethingWithPojo(pojo)) // no guarantees about the threading/scheduling in doSomethingWithPojo()
.subscribe(pojo -> System.out.println("Got a pojo: " + pojo.toString()));
或更可能:
Pojo myPojo = new Pojo("old name");
getNameFromSomewhere() // intentionally no guarantee what scheduler or thread this is observed on for this example
.doOnNext(pojo -> pojo.setName("new name"))
.flatMap(pojo -> doSomethingWithPojo(pojo)) // again, no guarantees about the threading inside this call
.subscribe(pojo -> (), error -> System.out.println("Error handling goes here"));
假设Pojo对象是纯数据对象,没有副作用,看起来像:
class Pojo {
private String name;
public Pojo(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
此模式是否可以避免细微的线程错误?
我能想到的最大的障碍是记忆障碍,但我还没有足够的专家来忽略某些事情我可能不知道的想法。
例如,是否存在内存屏障,以便在doOnNext()
调用中发生突变后,所有写入都将被提交,并被flatMap内部doSomethingWithPojo()
中发生的任何事情所吸收?
简而言之:这些模式安全吗?
(我们的代码库是RxJava 1,但是这个问题同样适用于RxJava 2)
答案 0 :(得分:0)
取决于上游是否同时发射元素。 This SO显示了Subject
如何以非线程安全方式运行的示例。
AtomicInteger counter = new AtomicInteger(); // Thread-safe // SerializedSubject<Object, Object> subject = PublishSubject.create().toSerialized(); // Not Thread Safe PublishSubject<Object> subject = PublishSubject.create(); Action1<Object> print = (x) -> System.out.println(Thread.currentThread().getName() + " " + counter); Consumer<Integer> sleep = (s) -> { try { Thread.sleep(s); } catch (InterruptedException e) { e.printStackTrace(); } }; subject .doOnNext(i -> counter.incrementAndGet()) .doOnNext(i -> counter.decrementAndGet()) .doOnNext(print) .filter(i -> counter.get() != 0) .doOnNext(i -> { throw new NullPointerException("Concurrency detected"); } ) .subscribe(); Runnable r = () -> { for (int i = 0; i < 100000; i++) { sleep.accept(1); subject.onNext(i); } }; ExecutorService pool = Executors.newFixedThreadPool(2); pool.execute(r); pool.execute(r);