"不可能" NPE处于多线程情况

时间:2017-03-29 17:26:39

标签: java android multithreading java-8 rx-java2

我在Android应用中有一些固有的异步代码。我正在使用RxJava2。班级Thing不受我的控制(但ThingFactory是)。在一种方法(createThing())中,实例化新的ThingThing的构造函数可以完成一些工作,并在完成后通过回调onThingInitialized()通知我们。在调用回调时,我们应该保证thing存在。在回调中,我计划在单独的线程上进行工作(在这种情况下,使用RxJava2,但我认为它不重要)。这段代码中没有任何地方可以调用类似thing = null的内容。所以,一旦设定,它就会永远定下来。

我向它投了volatile因为实例 得到了更新,但从未被取消。如果我误用了它,请随意指责我。

public class UsesAThing implements ThingCallbacks {

    private volatile Thing thing; // I feel like I don't understand 'volatile'

    // I call this method
    public void createThing() {
        thing = thingFactory.newThing(param1, param2);
    }

    // Thing's constructor does some work and notifies us when it's done
    @Override
    public void onThingInitialized() {
        // Called on main thread, but I want to do some IO work, so:
        Schedulers.io().scheduleDirect(() -> {
            thing.doStuff(); // NPE!
        });
    }
}

那里的NPE怎么样?

修改

Thing的构造函数以异步方式工作。正如我所说,这是在Android环境中,所以它实际做的工作是绑定到Service。当绑定Service时,其ServiceConnection::onServiceConnected()回调会被点击,其实际上会触发AsyncTask onPostExecute(),在其onThingInitialized()回调中,会调用Flowable.just(1) .subscribeOn(Schedulers.io()) .subscribe(i -> createThing()); 回调

编辑2:

我还应该注意到这个NPE不会一直发生。我已经完成了数百次这段代码,而且我只看过它一次。

编辑3:示例呼叫代码

我没有提供示例代码,因为它的内容与人们想象的一样简单,但这就是它的样子:

{{1}}

1 个答案:

答案 0 :(得分:4)

如果我理解你的评论,则在工作线程中调用createThing()。在Thing构造函数启动导致回调的事件序列之后,线程调度程序可能会暂停此工作线程,但之前 newThing()返回并分配thing。如果整个回调序列在调用createThing()的线程再次运行之前运行,您将看到此NPE。

要测试此理论,首先要创建一个重复运行的测试来重现该问题。然后更改它,以便在主线程中调用createThing()并查看问题是否消失。这将是一种解决方法,而不是修复。但真正的解决方法是不要在Thing的构造函数中进行操作,而您所说的是您无法控制的。