首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何诊断ConcurrentModificationException

如何诊断ConcurrentModificationException
EN

Stack Overflow用户
提问于 2016-05-23 17:40:31
回答 1查看 814关注 0票数 1

我在一份分析报告中得到了下面的错误,我很难弄清楚它是从哪里来的,或者是如何解决的。

我感到困惑的原因是,崩溃似乎引用了它-self的Volley库,而不是我实际编写的任何代码(崩溃中没有任何代码指向我的代码)。

有谁知道我怎样或者怎样才能解决这场坠机?

如有任何建议,将不胜感激。

致命错误:

代码语言:javascript
复制
Fatal Exception: java.util.ConcurrentModificationException
       at java.util.HashMap$HashIterator.nextEntry(HashMap.java:787)
       at java.util.HashMap$ValueIterator.next(HashMap.java:819)
       at com.android.volley.toolbox.ImageLoader$4.run(ImageLoader.java:464)
       at android.os.Handler.handleCallback(Handler.java:739)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:5527)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)

来源:

代码语言:javascript
复制
public class VolleyManager {
    private static final String TAG = VolleyManager.class.getSimpleName();

    /** Number of network request dispatcher threads to start. */
    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;

    private static VolleyManager mInstance;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private static Context mContext;

    private VolleyManager(Context context) {
        mContext = context.getApplicationContext();
        mRequestQueue = getRequestQueue();
    }

    public static synchronized VolleyManager getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new VolleyManager(context);
        }
        return mInstance;
    }

    @SuppressWarnings("deprecation")
    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            File cacheDir = new File(FMCacheManager.getCacheBaseDir(mContext));

            String userAgent = "volley/0";
            try {
                String packageName = mContext.getPackageName();
                PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
                userAgent = packageName + "/" + info.versionCode;
            } catch (NameNotFoundException ignore) {
            }

            HttpStack stack = new HurlStack();
            Network network = new BasicNetwork(stack);

            HandlerThread mHandlerThread = new HandlerThread(TAG, android.os.Process.THREAD_PRIORITY_BACKGROUND);
            mHandlerThread.start();

            ResponseDelivery delivery = new ExecutorDelivery(new Handler(mHandlerThread.getLooper()));
            RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network, DEFAULT_NETWORK_THREAD_POOL_SIZE, delivery);

            queue.start();

            mRequestQueue = queue;
        }
        return mRequestQueue;
    }


    public ImageLoader getImageLoader() {
        getRequestQueue();
        if (mImageLoader == null) {
            mImageLoader = new ImageLoader(this.mRequestQueue,
                    new LruBitmapCache());
        }
        return this.mImageLoader;
    }

    public <T> void addToRequestQueue(Request<T> req, String tag) {
        if (req != null) {
            Log.d(TAG, "request: " + req.getUrl());

            // set the default tag if tag is empty
            req.setTag(FMUtils.isNullOrEmpty(tag) ? TAG : tag);

            getRequestQueue().add(req);
        }
    }

    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }

}
EN

回答 1

Stack Overflow用户

发布于 2016-05-23 18:18:32

是的,堆栈跟踪表明崩溃发生在ImageLoaderrun()方法中,并且与在HashMap上迭代有关。

您可以看到(某些版本的) ImageLoader.java 在这里。每一个循环都是这样的:

代码语言:javascript
复制
for (BatchedImageRequest bir : mBatchedResponses.values()) {
    for (ImageContainer container : bir.mContainers) {
        // If one of the callers in the batched request canceled the request
        // after the response was received but before it was delivered,
        // skip them.
        if (container.mListener == null) {
            continue;
        }
        if (bir.getError() == null) {
            container.mBitmap = bir.mResponseBitmap;
            container.mListener.onResponse(container, false);
        } else {
            container.mListener.onErrorResponse(bir.getError());
        }
    }
}

现在,如果另一个线程在迭代时修改mBatchedResponses.values()bir.mContainers,则会出现ConcurrentModificationException。它们不是“线程安全”集合。

最近的另一次讨论,它指出任何同时(并行)图像加载操作都应该使用单独的ImageLoader实例。费尔南多·贾斯科维奇写道:

您必须实现两个ImageLoaders,一个用于缩略图,另一个用于全分辨率图像。

因此,您可以检查是否在自己的代码中启动任何并行图像下载操作,查看其他讨论并遵循推荐的方法。

至于“如何诊断ConcurrentModificationException”的一个更通用的答案:查看堆栈跟踪,查看确切的代码文件名和行号。如果它在一个for-每一个循环中迭代一个集合,那么您可能同时在另一个线程中修改该集合。这种情况可能只是偶尔发生,而且在很长一段时间内没有人注意到。在修改上述每个循环中的集合时,也会发生同样的异常,例如,在这次讨论中

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37397276

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档