ArrayMap java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Object[]
错误堆栈:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Object[]
at android.support.v4.util.SimpleArrayMap.allocArrays(SourceFile:183)
at android.support.v4.util.SimpleArrayMap.put(SourceFile:437)
错误原因:
由于SimpleArrayMap 里面使用了一个静态变量的缓存,mBaseCache,
static Object[] mBaseCache;
该变量默认有两个数据,第1个元素是一个object[],用于存放上次的缓存的mBaseCache
第二个元素是int[],用于存在hash。具体赋值代码可以看下面
synchronized (ArrayMap.class) {
if (mBaseCacheSize < CACHE_SIZE) {
array[0] = mBaseCache;
array[1] = hashes;
for (int i=(size<<1)-1; i>=2; i--) {
array[i] = null;
}
mBaseCache = array;
mBaseCacheSize++;
if (DEBUG) Log.d(TAG, "Storing 1x cache " + array
+ " now have " + mBaseCacheSize + " entries");
}
}
使用该数组的地方在:
SimpleArrayMap 的allocArrays 方法里
synchronized (ArrayMap.class) {
if (mBaseCache != null) {
final Object[] array = mBaseCache;
mArray = array;
mBaseCache = (Object[])array[0];
mHashes = (int[])array[1];
array[0] = array[1] = null;
mBaseCacheSize--;
if (DEBUG) Log.d(TAG, "Retrieving 1x cache " + mHashes
+ " now have " + mBaseCacheSize + " entries");
return;
}
}
下面这段代码是有风险的,如果mBaseCache 在多线程被修改了,就会把ClassCastException 异常。
mBaseCache = (Object[])array[0];
解决方法:
如果项目某个地方报这个错误,请把这个地方的ArrayMap替换成 HasMap. HasMap 多线程不会崩溃,虽然,他不是特别完好的支持。不需要把项目中所有的地方都替换掉,没有必要。单独线程,ArrayMap 完全没有问题。
错误复现:这个复现起来超级麻烦,我花了一周的时间,才找到复现的漏洞,分享给大家:
/**
* 复现该问题 用了四个线程
* java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Object[]
* at android.support.v4.util.SimpleArrayMap.allocArrays(SimpleArrayMap.java:157)
* at android.support.v4.util.SimpleArrayMap.put(SimpleArrayMap.java:399)
* at com.example.fragment.MainFragment$14.run(MainFragment.java:280)
* 1.首先 线程1 执行到put 方法的
* mArray[index<<1] = key;
* mArray[(index<<1)+1] = value;
* mSize++;
* return null;
* 最上面这个位置 目的是让这个数组不再是空的
*
* 2.执行线程2 也执行到
* mArray[index<<1] = key;
* mArray[(index<<1)+1] = value;
* mSize++;
* return null;
* 最上面这个位置 目的是让这个put 的东西,放在第0个位置,因为put里面会生成index,
* 让两个线程都放到index 是0 的位置
*
* 3.把线程1执行完,这样数据里面已经放进去一个数据了
*
* 4.执行线程3 到removeAt 方法的 freeArrays 的 mBaseCache = array; 之前
* public V removeAt(int index) {
* final Object old = mArray[(index << 1) + 1];
* if (mSize <= 1) {
* // Now empty.
* if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
* freeArrays(mHashes, mArray, mSize);
*
* mBaseCache = array;----------- freeArrays
*
* 这个的目的是调用freeArray 方法,让当前的map释放当前的数组。这样就可以生成mBaseCache了
*
* 5.把线程2 执行完
* 这样就会把mBaseCache 赋值的数组,重新赋值
*
* 6.把线程3执行完
* ok,现在mBaseCache已经被污染了
*
* 7.执行线程4
*
*/
private void CMETestCastException() {
final ArrayMap testArrayMap = new ArrayMap();
final ArrayMap testArrayMap2 = new ArrayMap();
new Thread("线程1"){
@Override
public void run() {
super.run();
testArrayMap.put("2324","fffff");
}
}.start();
new Thread("线程2"){
@Override
public void run() {
super.run();
testArrayMap.put("test","string");
}
}.start();
new Thread("线程3"){
@Override
public void run() {
super.run();
testArrayMap.removeAt(0);
}
}.start();
new Thread("线程4"){
@Override
public void run() {
super.run();
testArrayMap2.put("aaa","string");
}
}.start();
}
复现这个问题的时候,关键是把mBaseCache 污染掉。这里四个线程的话,需要调试,调试步骤就是上面我注释的。
总结:
如果当前的map 会有多个线程访问,请使用HasMap. 该问题,google 并没有解决。在高版本上,直接扔CME ConcurrentModificationException.
ArrayMap java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Object[]的更多相关文章
- java.lang.ClassCastException: oracle.sql.TIMESTAMP cannot be cast to java.sql.Timestamp
http://stackoverflow.com/questions/13269564/java-lang-classcastexception-oracle-sql-timestamp-cannot ...
- java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to android.widget.TextView
最近在学习drawerLayout时,遇到这个bug.如下示: java.lang.ClassCastException: android.widget.RelativeLayout cannot b ...
- [Ljava.lang.String; cannot be cast to java.lang.String报错的原因
完整错误信息: java.lang.ClassCastException: [Ljava.lang.String; cannot be cast to java.lang.String 报这个错的原因 ...
- java.lang.ClassCastException: android.app.Application cannot be cast to
出这个异常的原因是在项目中添加了新lication类(public class Application extends lication)之后,没有在AndroidManifest.xml中添加该类的 ...
- 关于android使用ksoap2报Caused by: java.lang.ClassCastException: org.ksoap2.SoapFault cannot be cast to org.ksoap2.serialization.SoapObject
Caused by: java.lang.ClassCastException: org.ksoap2.SoapFault cannot be cast to org.ksoap2.serializa ...
- java.lang.ClassCastException: oracle.sql.CLOB cannot be cast to oracle.sql.CLOB
错误现象: [framework] 2016-05-26 11:34:53,590 -INFO [http-bio-8080-exec-7] -1231863 -com.dhcc.base.db.D ...
- java.lang.ClassCastException: android.widget.TextView cannot be cast to android.widget.EditText
Caused by: Java.lang.ClassCastException: Android.widget.TextView cannot be cast to android.widget.Ed ...
- 安卓出现错误: java.lang.ClassCastException: android.widget.TextView cannot be cast to android.widget.EditText
Caused by: Java.lang.ClassCastException: Android.widget.TextView cannot be cast to android.widget.Ed ...
- java.lang.ClassCastException:android.widget.Button cannot be cast to android.widget.ImageView
今天遇到一个错误也不知道怎么回事,上网搜了一下: 出现的问题是:java.lang.ClassCastException:android.widget.Button cannot be cast to ...
随机推荐
- Kubernetes stateful set讲解以及一个基于postgreSQL的具体例子
Stateful Set是Kubernetes 1.9版本新引入的一个概念,用于管理有状态的应用. Kubernetes官方文档: https://kubernetes.io/docs/concept ...
- c++基础知识_c++11 类默认函数的控制:"=default" 和 "=delete"函数
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <vecto ...
- cocos2dx-打敌人游戏(一)
參照视频: http://v.youku.com/v_show/id_XNjk5MzExNDYw.html 1.參照前一篇文章创建新项目: http://blog.csdn.net/simakongc ...
- python:协程
1,如何实现在两个函数之间的切换? def func1(): print(l) yield print(3) yield def func2(): g =func1() next(g) print(2 ...
- winform 实现彩票功能
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/MrTraum/article/details/32702319 watermark/2/text/a ...
- 【洛谷P1073】[NOIP2009]最优贸易
最优贸易 题目链接 看题解后感觉分层图好像非常NB巧妙 建三层n个点的图,每层图对应的边相连,权值为0 即从一个城市到另一个城市,不进行交易的收益为0 第一层的点连向第二层对应的点的边权为-w[i], ...
- 【luogu P2324 [SCOI2005]骑士精神】 题解
题目链接:https://www.luogu.org/problemnew/show/P2324 不懂怎么剪枝,所以说,,我需要氧气.. 第一道A* // luogu-judger-enable-o2 ...
- 任务学习-ucos
1.任务(task)也称作一个线程: 2.一个任务有5种状态:休眠,就绪,运行,挂起,被中断 休眠:任务驻留在程序空间中,还没有交给ucos管理,把任务交给ucos 是通过调用OSTaskCreate ...
- 终于好像懂motan了!!!
我依稀记得,刚到公司的时候,锋哥让我学习Maven,spring,spring MVC,mybatis,RPC:motan,Xdiamond,Jenkins,redis和Kafka.快3个月了,目前只 ...
- Openresty最佳案例 | 第2篇:Lua入门
转载请标明出处: http://blog.csdn.net/forezp/article/details/78616622 本文出自方志朋的博客 什么是lua Lua 是一种轻量小巧的脚本语言,用标准 ...