对同一类中的方法进行无参数调用会产生NullPointerException

时间:2013-08-19 13:07:11

标签: java android multithreading nullpointerexception synchronized

我已经看到了一些奇怪的错误,但这一次,我完全难过了。尝试在同一个类中调用方法时,我收到NullPointerException。

首先,一些代码。让我们从违规行开始吧。当然,这种方法比这更长,但这是它的开始,所有这些都是相关的:

protected synchronized void checkTransfers() {
    if (isPaused())
        return;
}

isPaused是一个简单的getter方法:

protected boolean isPaused() {
    return paused.get();
}

为了完整性'缘故:

protected AtomicBoolean paused = new AtomicBoolean(false);

现在问题是这个代码运行的时间大约有50%,它只会在if (isPaused())行上抛出NullPointerException,这对我来说没有意义。 checkTransfers()方法与isPaused()位于同一类中。我的同事试图通过提及问题可能是在涉及多线程的问题,如果例如另一个线程已经获得CPU时间并删除其对该对象的引用,但该对象应该永远不会在我的代码中的任何地方丢失它的引用。另外:NPE触发后,this仍然正确定义。

堆栈跟踪如下:

  

主@ 830013674640" prio = 5可运行     java.lang.Thread.State:RUNNABLE       在com.omines.android.communicationmanager.CommunicationManager.checkTransfers(CommunicationManager.java:125)       在com.omines.android.communicationmanager.DownloadTask.onPostExecute(DownloadTask.java:105)       在com.omines.android.communicationmanager.DownloadTask.onPostExecute(DownloadTask.java:20)       在android.os.AsyncTask.finish(AsyncTask.java:602)       在android.os.AsyncTask.access $ 600(AsyncTask.java:156)       在android.os.AsyncTask $ InternalHandler.handleMessage(AsyncTask.java:615)       在android.os.Handler.dispatchMessage(Handler.java:99)       在android.os.Looper.loop(Looper.java:154)       在android.app.ActivityThread.main(ActivityThread.java:4945)       at java.lang.reflect.Method.invokeNative(Method.java:-1)       在java.lang.reflect.Method.invoke(Method.java:511)       在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:784)       在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)       在dalvik.system.NativeStart.main(NativeStart.java:-1)

checkTransfers()中的第125行是上面的if语句。

有没有人知道会导致这样的行为?

1 个答案:

答案 0 :(得分:1)

是的,这需要一些邪恶的调试,但我似乎找到了问题。发布它以防以后可以帮助别人。

首先,您需要更多地了解我的方法。这是完整的:

protected synchronized void checkTransfers() {
    if (isPaused())
        return;
    while (transferQueue.peek() != null && (transferQueue.peek().priority == PRIORITY_URGENT ||
            (transferSemaphore.availablePermits() > maxConcurrentTransfers)))
    {
        CommunicationTask ct = transferQueue.poll();
        if (ct != null)
        {
            if (ct instanceof DownloadTask)
                currentlyDownloading.add((DownloadTask)ct);
            ct.execute();
        }
    }
}

我发现它不会在方法开始时抛出异常。事实证明,在异常之前,它将遍历整个方法一次,然后调试器将跳转到方法的第一行并抛出NullPointerException而不是退出它。

有了可以使用的东西,我发现只要不是DownloadTask而是上传任务执行就会发生这种情况。事实证明,我的所有DownloadTasks都知道他们的调用Activity,以便他们可以显示进度对话框,但UploadTask总是传递null而不是对调用者的引用。在旧版本的代码中,这很好,但在最近的一些更改后,显然它成了一个问题。

我仍然不确定为什么每当我的任务试图访问对其调用活动的不存在的引用时我都不会获得异常,但显然在看似无关的代码中触发异常是正常的行为

感谢您抽出宝贵时间阅读我的问题并尝试提供帮助。我希望至少我的回答可以帮助别人。