ArrayList为什么是线程不安全的

提到线程安全我们应该第一时间想到锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用,所以通过加锁我们就可以保证一个线程的安全性,list接口下面有两个实现,一个是arraylist,另外一个是vector。 从源码的角度来看,因为vector的方法前加了,synchronized 关键字,也就是同步的意思,sun公司希望vector是线程安全的,而希望arraylist是高效的。

在多个线程进行add操作时可能会导致elementData数组越界。具体逻辑如下:

ArrayList 默认数组大小为 10。假设现在已经添加进去 9 个元素了,size = 9。

  1. 线程 A 执行完 add 函数中的ensureCapacityInternal(size + 1)挂起了。
  2. 线程 B 开始执行,校验数组容量发现不需要扩容。于是把 "b" 放在了下标为 9 的位置,且 size 自增 1。此时 size = 10。
  3. 线程 A 接着执行,尝试把 "a" 放在下标为 10 的位置,因为 size = 10。但因为数组还没有扩容,最大的下标才为 9,所以会抛出数组越界异常 ArrayIndexOutOfBoundsException

案例分析

public static void main(String[] args) throws InterruptedException {
   final List<Integer> list = new ArrayList<Integer>();
   // 线程A将0-1000添加到list
   new Thread(new Runnable() {
       public void run() {
          for (int i = 0; i < 1000 ; i++) {
               list.add(i);
            try {
               Thread.sleep(1);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }
 }).start();
 // 线程B将1000-2000添加到列表
 new Thread(new Runnable() {
     public void run() {
        for (int i = 1000; i < 2000 ; i++) {
            list.add(i);
         try {
             Thread.sleep(1);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
  }
 }).start();
 Thread.sleep(1000);
      // 打印所有结果
       for (int i = 0; i < list.size(); i++) {
       System.out.println("第" + (i + 1) + "个元素为:" + list.get(i));
      }
}

测试结果:

可以看到第11个元素的值为null,数组越界

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值