ArrayList线程不安全的例子

线程安全就是多线程访问时,采用加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据时脏数据。List接口下有两个实现,一个是ArrayList,另一个是Vector。从源码角度来看,因为Vector的方法前加了synchronized关键字,也就是同步。ArrayList是高效的,Vector则是线程安全的。

ArrayList不是线程安全的举个例子:一个ArrayList,在添加一个元素的时候,它有大体上有两步来完成:

  1. 在内部数组的size索引处存放此元素;
  2. 增大size的值

在单线程情况下,如果size是0,添加一个元素之后,此元素在位置0,而且size=1;

在多线程情况下,假设有两个线程,线程A现将元素放在0位置。但是此时CPU调度线程A暂停线程B得到运行机会,线程B也向ArrayList中添加元素,因为此时size仍然等于0(注意线程A只完成了添加的第一步,后面修该size的步骤还没做),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加size的值。对于这个ArrayList来说,元素实际上只有一个,存放在位置0,二size却等于2。

附:ArrayList的add方法:

 public boolean add(E e) {
// Increments modCount!!
ensureCapacityInternal(size + 1);
// 现在size处放置元素, 然后在增加size
elementData[size++] = e;
return true;
}

测试ArrayList线程不安全的demo:

 public class UnsafeArrayListDemo implements Runnable {
private List<Integer> list = new ArrayList<Integer>(); public void run() {
try {
Thread.sleep((int)Math.random());
} catch (Exception e) {
e.printStackTrace();
}
list.add(1);
} public static void main(String[] args) throws Exception {
ThreadGroup group = new ThreadGroup("group");
UnsafeArrayListDemo unsafeArrayListDemo = new UnsafeArrayListDemo();
for(int i=0; i<10000; i++) {
Thread t = new Thread(group, unsafeArrayListDemo, String.valueOf(i));
t.start();
}
// 等待线程组执行完毕
while(group.activeCount() > 0) {
Thread.sleep(100);
}
System.out.println(unsafeArrayListDemo.list.size());
}
}

现在看下Vector中的add方法:

 public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}

基本上和ArrayList一样,都是先添加,然后对size自增,唯一不同的是这个方法上加了关键字synchronized。可以在ArrayList的demo换成Vector来测试(本人已经测试过了,就不附代码了,直接替换ArrayList就好了)。Vector相对于ArrayList也会很暴力,为了线程安全就对方法加上了synchronized。

Vector的方法在单个进行调用的时候虽然是线程安全的,但是进行方法的复合操作的时候仍然是线程不安全的,还需要客户端来进行加锁。

Vector复合操作不安全的例子

 public class VectorDemo {
// 获取最后一个元素
public static Object getLast(Vector list) {
int lastIndex = list.size() - 1;
return list.get(lastIndex);
}
// 删除最后一个元素
public static void deleteLast(Vector list) {
int lastIndex = list.size() - 1;
list.remove(lastIndex);
}
}

像这种先获取值,然后进行操作都是不安全的,简单的方法就是在方法内部进行加锁。问题来了,怎么加锁呢?

最新文章

  1. 火狐----此地址使用了一个通常用于网络浏览以外的端口。出于安全原因,Firefox 取消了该请求。
  2. history 查看历史操作记录在shell脚本执行中无法显示问题
  3. GLSL 中的光照计算
  4. Cocos2d-x 3.1 内存管理机制
  5. 保护模式下GDTR,LDTR,全局描述符表,局部描述符表和选择器的关系
  6. Java JDK8 安装及环境变量配置
  7. ios objection
  8. SSO单点登录(转载)
  9. 整个网站灰度显示css代码
  10. spark 编程向导
  11. [ext4]03 磁盘布局 – Flexible group分析
  12. VB6之摄像头控制
  13. VPS修改SSH端口不小心把自己给墙掉的一般解决办法
  14. mmap函数实现
  15. css响应式
  16. 分布式事务之深入理解什么是2PC、3PC及TCC协议?
  17. 第五周作业--测试与版本发布(Alpha版本)
  18. WINCE 下载地址(转)
  19. discuz 文件模板edit
  20. 条件随机场(CRF)原理和实现

热门文章

  1. Oracle VPD策略示例
  2. Android RoboGuice开源框架、Butter Knife开源框架浅析
  3. 转 HystrixDashboard服务监控、Turbine聚合监控
  4. javascript 20个正则表达式
  5. Android 4.1的新特性介绍
  6. win764bit系统plsqldeveloper11连接oracle11g64bit配置方法
  7. springboot + mybatis-pagehelper 参数查询不分页的bug。。。
  8. K8s 介绍
  9. UML的通用机制(三)
  10. Android API Guides---Drag and Drop