并发库应用之十二 & 常用集合问题汇总
2017-03-10 18:24
260 查看
1. List遍历时修改报错
别的先什么都不说,直接上代码看看就知道了:
运行以上代码报错如下所示:
![](https://images2015.cnblogs.com/blog/980882/201703/980882-20170310165451451-991401901.png)
查看jdk源代码中AbstractList的checkForComodification方法的源码,分析产生ConcurrentModificationException异常的原因发现错误原因了,具体解释请看下面一张图片:
![](https://images2015.cnblogs.com/blog/980882/201703/980882-20170310175429420-1031473862.png)
要想解决以上问题,需要使用并发集合,对应ArrayList的并发集合为:CopyOnWriteArrayList 。具体详情介绍请看下一篇:并发应用之十三 & 并发集合应用
2. HashMap多线程下死循环问题
Race Condition(也叫做资源竞争),是多线程编程中比较头疼的问题。特别是Java多线程模型当中,经常会因为多个线程同时访问相同的共享数据,而造成数据的不一致性。为了解决这个问题,通常来说需要加上同步标志“synchronized”,来保证数据的串行访问。但是“synchronized”是个性能杀手,过多的使用会导致性能下降,特别是扩展性下降,使得你的系统不能使用多个CPU资源。 这是我们在性能测试中经常遇见的问题。
但是:有时候使用HashMap并没有使用 synchronized 同步反而性能下降很厉害,几乎将CPU资源打满了。
于是做了好几轮测试与验证,具体做法如下:
1. 让并发用户数量为1,不停的运行10分钟,结果没有发现这种情况;
2. 接着我们让50个并发用户同时运行,但是只运行在一个CPU上(通过psrset),结果也没有出现死循环状态。
3. 只要并发用户数量超过10个,运行的CPU超过两个,不到2分钟就出现死循环。一旦死循环出现,大量CPU资源被白白浪费,性能会非常非常的差。
通过上面的试验我们可以很肯定的判断,是由于并发控制不好,导致数据的不一致,引起的死循环。值得一提的是,HashMap不是一个线程安全的数据结构,要用到多个线程中去,需要自己加上同步标志,为什么会死循环呢,看看下面HashMap中get函数的源代码:
get函数会根据key的hashcode来锁定多个对象,并且遍历这些对象来找到key所对应的对象。当多个线程不安全的修改HanshMap数据结构的时候,有可能使得这个函数进入死循环。
建议可以使用并发集合:ConcurrentHashMap 或在使用HanshMap的时候加上同步标志!
具体遍历这些对象为什么会发生死循环呢,其实HashMap底层循环还是采用迭代器进行的,当循环取数据的时候,如果有其他线程在修改确实可能会发生死循环,具体过程我这里用伪代码进行讲解说明:(假设数据集合总个数为4个)
总结:在平时使用集合编写代码的时候,以上两个错误是我们经常遇见的。如果真发生了这样的情况,那么我建议直接换用线程并发集合,这样可以解决以上的问题。
提示:欢迎继续参看我相关的下一篇博客:并发库应用之十三 & 并发集合类的应用
别的先什么都不说,直接上代码看看就知道了:
1 public class ListTest { 2 public static void main(String[] args) { 3 List<Integer> list = new ArrayList<Integer>(); 4 list.add(1);list.add(2);list.add(3);list.add(4); 5 Iterator iterator = list.iterator(); 6 while(iterator.hasNext()) { 7 int currentInt = Integer.parseInt(iterator.next().toString()); 8 if (currentInt == 2) { 9 list.remove(currentInt); 10 } else { 11 System.out.println(currentInt); 12 } 13 } 14 }
运行以上代码报错如下所示:
![](https://images2015.cnblogs.com/blog/980882/201703/980882-20170310165451451-991401901.png)
查看jdk源代码中AbstractList的checkForComodification方法的源码,分析产生ConcurrentModificationException异常的原因发现错误原因了,具体解释请看下面一张图片:
![](https://images2015.cnblogs.com/blog/980882/201703/980882-20170310175429420-1031473862.png)
要想解决以上问题,需要使用并发集合,对应ArrayList的并发集合为:CopyOnWriteArrayList 。具体详情介绍请看下一篇:并发应用之十三 & 并发集合应用
2. HashMap多线程下死循环问题
Race Condition(也叫做资源竞争),是多线程编程中比较头疼的问题。特别是Java多线程模型当中,经常会因为多个线程同时访问相同的共享数据,而造成数据的不一致性。为了解决这个问题,通常来说需要加上同步标志“synchronized”,来保证数据的串行访问。但是“synchronized”是个性能杀手,过多的使用会导致性能下降,特别是扩展性下降,使得你的系统不能使用多个CPU资源。 这是我们在性能测试中经常遇见的问题。
但是:有时候使用HashMap并没有使用 synchronized 同步反而性能下降很厉害,几乎将CPU资源打满了。
于是做了好几轮测试与验证,具体做法如下:
1. 让并发用户数量为1,不停的运行10分钟,结果没有发现这种情况;
2. 接着我们让50个并发用户同时运行,但是只运行在一个CPU上(通过psrset),结果也没有出现死循环状态。
3. 只要并发用户数量超过10个,运行的CPU超过两个,不到2分钟就出现死循环。一旦死循环出现,大量CPU资源被白白浪费,性能会非常非常的差。
通过上面的试验我们可以很肯定的判断,是由于并发控制不好,导致数据的不一致,引起的死循环。值得一提的是,HashMap不是一个线程安全的数据结构,要用到多个线程中去,需要自己加上同步标志,为什么会死循环呢,看看下面HashMap中get函数的源代码:
1 public V get(Object key) { 2 if (key == null) 3 return getForNullKey(); 4 int hash = hash(key.hashCode()); 5 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null;e = e.next) { 6 Object k; 7 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 8 return e.value; 9 } 10 return null; 11 }
get函数会根据key的hashcode来锁定多个对象,并且遍历这些对象来找到key所对应的对象。当多个线程不安全的修改HanshMap数据结构的时候,有可能使得这个函数进入死循环。
建议可以使用并发集合:ConcurrentHashMap 或在使用HanshMap的时候加上同步标志!
具体遍历这些对象为什么会发生死循环呢,其实HashMap底层循环还是采用迭代器进行的,当循环取数据的时候,如果有其他线程在修改确实可能会发生死循环,具体过程我这里用伪代码进行讲解说明:(假设数据集合总个数为4个)
count = 4; while (hasNext()) { next();//取出对应的数据 cursor++;//对应版本号 } hasNext() { if (cursor == count) { return false;//取到最后一个元素了 } return true; } remove() { count--; cursor++; } /** * 如果正好遍历到最后一个元素,正好有其他线程执行remove操作,则count=3 * 这样 cursor 永远不等于 count 了,从上面 hasNext()判断方法看,判断是否有下一个值就永远是真,即为死循环 */
总结:在平时使用集合编写代码的时候,以上两个错误是我们经常遇见的。如果真发生了这样的情况,那么我建议直接换用线程并发集合,这样可以解决以上的问题。
提示:欢迎继续参看我相关的下一篇博客:并发库应用之十三 & 并发集合类的应用
相关文章推荐
- 常用软件推荐集合汇总──&nbsp;为新手指…
- 01-常用对象API(集合框架-泛型-概述) 1 2 02-常用对象API(集合框架-泛型-擦除&补偿) 03-常用对象API(集合框架-泛型-在集合中的应用)
- 常用软件推荐集合汇总──&nbsp;为新手指…
- Redis中7种集合类型应用场景&redis常用命令
- 设计模式的实际应用――在C#中解决单客户端窗口数据并发问题
- MySql 常用问题汇总
- ORACLE常用问题1000问(之十二)
- 使用Struts开发Web应用常见的一些问题汇总
- 关于并发用户与集合点的问题
- 小程序&小问题&小算法集合帖
- TStringList 常用方法与属性&DelimitedText空格问题
- 转-数据库应用基础系列-第2章 并发操作的一致性问题 (2)
- 重构方法进阶(十二):代码常用重构方法(临时变量内联化&以查询取代临时变量)
- 【Android】调用系统应用常用uri & intent设置
- 当web应用中面临大数据量同时并发量比较大的情况下性能是一个尤为重要的问题,面对性能优化我们应从何做起,在哪些方面做优化呢?
- 集合的应用常用方法笔记
- CCF问题集合2:CCF集成winform应用,如何嵌入CCF的mainPanel
- 转-数据库应用基础系列-第2章 并发操作的一致性问题 (1)
- CITRIX常用问题汇总(我自己遇到的问题的解决方法)
- Linux维护之Grub应用与问题汇总