java 多线程集合操作_多线程中使用Java集合类
Java集合类中,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection。通常在这些情况下,迭代的结果是不确定的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常。执行该操作的迭代器称为快速失败 迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任意发生不确定行为的风险。
因此,当一个线程试图ArrayList的数据的时候,另一个线程对ArrayList在进行迭代的,会出错,抛出ConcurrentModificationException。
比如下面的代码:
finalList tickets =newArrayList();
for(inti =0; i <100000; i++) {
tickets.add("ticket NO,"+ i);
}
System.out.println("start1...");
for(inti =0; i <10; i++) {
Thread salethread = newThread() {
public voidrun() {
while(tickets.size() >0) {
tickets.remove(0);
System.out.println(Thread.currentThread().getId()+"Remove 0");
}
}
};
salethread.start();
}
System.out.println("start2...");
newThread() {
public voidrun() {
for(String s : tickets) {
System.out.println(s);
}
}
}.start();
上述程序运行后,会在某处抛出异常:
java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source) at mytest.mytestpkg.Tj$2.run(Tj.java:138)
Vector是线程同步的,那么把ArrayList改成Vector是不是就对了呢?
答案是否定的,事实上,无论是ArrayList还是Vector,只要是实现Collection接口的,都要遵循fail-fast的检测机制,即在迭代是时候,不能修改集合的元素。一旦发现违法这个规定就会抛出异常。
--------------------------------------------------------------------------------
事实上,Vector相对于ArrayList的线程同步,体现在对集合元素是否脏读上。即ArrayList允许脏读,而Vector特殊的机制,不会出现脏读,但是效率会很差。
举个例子,一个集合,有10个线程从该集合中删除元素,那么每个元素只可能由一个线程删除掉,不可能会出现一个元素被多个线程删除的情况。
比如下面的代码:
finalList tickets =newArrayList();
for(inti =0; i <100000; i++) {
tickets.add("ticket NO,"+ i);
}
System.out.println("start1...");
for(inti =0; i <10; i++) {
Thread salethread = newThread() {
public voidrun() {
while(true) {
if(tickets.size()>0)
System.out.println(Thread.currentThread().getId()+ tickets.remove(0));
else
break;
}
}
};
salethread.start();
}
for循环构造10个线程删除同一个集合中的数据,理论上只能删除100000次。但是运行完发现,输出的删除次数108494次,其中很多数据都是被多个线程删除,比如下面的输出片段:
17ticket NO,35721 14ticket NO,35699 11ticket NO,35721 18ticket NO,35721 17ticket NO,35729 11ticket NO,35729 14ticket NO,35729 17ticket NO,35729 14ticket NO,35734 17ticket NO,35734 13ticket NO,35721
可以看到35721,35729都被多个线程删除。这事实上就是出现了脏读。解决的办法就是加锁,使得同一时刻只有1个线程对ArrayList做操作。
修改代码,synchronized关键字,让得到锁对象的线程才能运行,这样确保同一时刻只有一个线程操作集合。
finalList tickets =newArrayList();
for(inti =0; i <100000; i++) {
tickets.add("ticket NO,"+ i);
}
System.out.println("start1...");
finalObject lock=newObject();
for(inti =0; i <10; i++) {
Thread salethread = newThread() {
public voidrun() {
while(true) {
synchronized(lock)
{
if(tickets.size()>0)
System.out.println(Thread.currentThread().getId()+ tickets.remove(0));
else
break;
}
}
}
};
salethread.start();
}
这样得到的结果就是准确的了。
当然,不使用synchronized关键字,而直接使用vector或者Collections.synchronizedList 也是同样效果:
finalList tickets =java.util.Collections.synchronizedList(newArrayList());
finalList tickets =newVector();
vector和Collections.synchronizedList 都是线程同步的,避免的脏读的出现。
posted on 2013-02-28 11:33 顺其自然EVO 阅读(175) 评论(0) 编辑 收藏
java 多线程集合操作_多线程中使用Java集合类相关推荐
- java基础----集合操作---实例----List集合的初始化
文章内容:最近使用LeapMotion进行软件开发时,使用到了java API---->List集合,使用过程中遇到了一些小bug,特写此博客记录相关心得. 程序编写背景:使用leapMotio ...
- java反射回调函数_用J2V8注册Java回调函数
J2V8是一套针对谷歌的V8 JavaScript引擎的Java绑定.J2V8的开发为Android平台带来了高效的Javascript的执行环境,taris.js 就是基于J2V8开发的.J2V8同 ...
- java 多线程不安全_多线程并发为什么不安全
一.线程安全定义 定义: 多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他操作,调用这个对象的行为都可以获得正确的结果 ...
- java 线程间通信方式_「转」JAVA多线程之线程间的通信方式
1. 同步 这里讲的同步是指多个线程通过synchronized关键字这种方式来实现线程间的通信. public class MyObject { synchronized public void m ...
- java list sublist方法_(转)Java 中 List.subList() 方法的使用陷阱
原文:http://blog.csdn.net/cleverGump/article/details/51105235 前言 本文原先发表在我的 iteye博客: http://clevergump. ...
- java使用集合存储过程_详解java调用存储过程并封装成map
详解java调用存储过程并封装成map 发布于 2020-5-1| 复制链接 摘记: 详解java调用存储过程并封装成map 本文代码中注释写的比较清楚不在单独说明,希望能帮助到大 ...
- java byte 判断相等_你真的了解Java中quot;==quot;和equals()的区别?
部分面试资料链接:https://pan.baidu.com/s/1qDb2YoCopCHoQXH15jiLhA 密码:jsam 想获得全部面试必看资料,关注公众号,大家可以在公众号后台回复" ...
- java读取csv文件_使用扫描仪读取Java中的CSV文件
java读取csv文件 We can use Java Scanner Class to read CSV File in java. 我们可以使用Java扫描程序类在Java中读取CSV文件. 读取 ...
- java cpu分配_容器中的Java:资源分配准则
短短几年内,容器就改变了软件行业的面貌.也许您已经到了在容器中运行Java的地步.那很棒!不幸的是,关于容器化Java应用程序的CPU和内存使用率,还有一些事情要注意,我将在下面概述. 本文假定总体上 ...
最新文章
- matlab 函数 向量参数,Scipy integrate(quad,quadration,nquad)不能集成向量参数化函数?等效函数(MATLAB works)...
- mysql 类似 user__类似于微博 用户最后一条动态的查询
- Mybatis分库分表扩展插件
- 将客户端移植到Linux和MAC OS
- 编写start脚本程序_使用可编写脚本的终结点遍历REST应用程序
- mysql select 效能_MYSQL的联合查询最好是少用,效能差异巨大
- javascript中数组、冒泡排序、函数及函数实参形参、arguments伪数组、异步函数等介绍
- 更多核心、更大内存、更低成本 AMD皓龙6000欲成云计算基石
- linux使用find命令_如何在Linux中使用FIND
- 在c语言中逗号运算符若不带括号,详解shell脚本括号区别--$()、$「 」、$「 」 、$(()) 、「 」 、「[ 」]...
- 混凝土静力受压弹性模量试验计算公式_混凝土试块检测要知道的9个技巧
- Centos7配置Samba服务实现与Windows文件共享
- Unity Android记录
- xp怎么删除计算机用户,WinXp系统如何删除用户账户?Xp系统删除用户账号的方法...
- 阿里系盒子英菲克i6八核 科学使用 笔记 (2015年12月26日成功)
- “AI复活了我的妻子,但我决定跟她说再见了”
- windows10系统超全面优化攻略
- 3DTouch Demo
- DIY 3D打印机——【有啥用啥版】
- 【Java】接口与继承