ArrayList 多线程报 数组越界异常

使用ArrayList在多线程环境可能会出现ArrayIndexOutOfBoundsException 异常,这篇文章就来看看为什么会出现这个错误。

场景还原

先看看下面的实例:

public class ArrayListConcurrent {

    private static List<Integer> numberList = new ArrayList<>(100000);

    public static class AddToArrayList extends Thread{
        int startNum = 0;

        public AddToArrayList(int startNum){
            this.startNum = startNum;
        }

        @Override
        public void run() {
            int count = 0;
            while (count < 1000000){
                numberList.add(startNum);
                startNum += 2;
                count++;
            }
        }
    }

    public static void main(String[] args) {
        Thread thread1 = new Thread(new AddToArrayList(0));
        Thread thread2 = new Thread(new AddToArrayList(1));
        thread1.start();
        thread2.start();
    }
}

在运行时报了如下的错误:

Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 174718
	at java.util.ArrayList.add(ArrayList.java:412)
	at com.yumoon.concurrent.ArrayListConcurrent$AddToArrayList.run(ArrayListConcurrent.java:24)
	at java.lang.Thread.run(Thread.java:722)

原因查找

下面是几组测试数据:
测试数据.png

我们打开ArrayList的412这一行,看看源码:

public boolean add(E e) {
  ensureCapacityInternal(size + 1);  // Increments modCount!!
  //这儿就是关键点,两个线程先后到达这儿,检查都发现不需要扩容,第一个线程在执行下面的步骤的时候没有问题,第二个就会数组越界了。
  elementData[size++] = e;		//这儿是412
  return true;
}

结合源码分析,看看ensureCapacityInternal 方法:

//这个方法就是用来判断是否需要扩容的方法
//结合前面的代码就是说只有有一个位置都可以
private void ensureCapacityInternal(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

比如 22 这儿报错就是因为 10 + 5 + (10+5)>> 1 = 22, (PS:需要熟悉ArrayList的扩容操作)

总结

在多线程环境下同时添加数据,两个及以上的线程执行完ensureCapacityInternal方法后都觉得不需要扩容,但是实际已经到了扩容的临界值的时候,就爆发了这个异常。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用toArray()方法将ArrayList转换成String数组,示例代码如下: ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("Hello"); arrayList.add("World"); String[] stringArray = arrayList.toArray(new String[arrayList.size()]); 其中,toArray()方法的参数是一个指定类型和长度的数组,如果该数组长度小于ArrayList的长度,则会创建一个新的数组。如果该数组长度大于或等于ArrayList的长度,则会将ArrayList中的元素复制到该数组中。最后,将该数组返回即可。 ### 回答2: 要将ArrayList转换成String数组,可以按照以下步骤进行操作: 1. 创建一个空的String数组,其长度与ArrayList的大小相同。 2. 使用循环遍历ArrayList中的每个元素。 3. 在循环的每一步中,将ArrayList中的元素转换为String类型,并将其存储到String数组的对应索引位置上。 4. 循环结束后,String数组中的每个元素都存储了相应的ArrayList元素的字符串表示。 以下是一个示例代码: ```java import java.util.ArrayList; public class ArrayListToStringArray { public static void main(String[] args) { ArrayList<String> arrayList = new ArrayList<String>(); arrayList.add("Hello"); arrayList.add("World"); arrayList.add("!"); String[] stringArray = new String[arrayList.size()]; for (int i = 0; i < arrayList.size(); i++) { stringArray[i] = arrayList.get(i); } // 打印String数组中的元素 for (int i = 0; i < stringArray.length; i++) { System.out.println(stringArray[i]); } } } ``` 运行以上代码,将会输出以下结果: ``` Hello World ! ``` 通过以上代码,我们将ArrayList转换为了String数组,并且可以方便地访问和处理String数组中的元素。 ### 回答3: 要将ArrayList转换为String数组,可以按照以下步骤进行操作: 1. 首先,创建一个与ArrayList大小相同的String数组,用于存储转换后的字符串。 2. 使用ArrayList的toArray()方法将其转换为Object数组。此时,ArrayList中的元素类型为Object。 3. 使用Arrays类的toString()方法将Object数组转换为String类型的数组。 4. 将转换后的String数组赋值给之前创建的String数组。 下面是一个示例代码展示如何将ArrayList转换为String数组: ```java import java.util.ArrayList; import java.util.Arrays; public class ArrayListToStringArray { public static void main(String[] args) { ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("apple"); arrayList.add("banana"); arrayList.add("orange"); // 创建与ArrayList大小相同的String数组 String[] stringArray = new String[arrayList.size()]; // 将ArrayList转换为Object数组 Object[] objectArray = arrayList.toArray(); // 将Object数组转换为String数组 stringArray = Arrays.toString(objectArray).split("[\\[\\]]")[1].split(", "); // 输出转换后的String数组 System.out.println(Arrays.toString(stringArray)); } } ``` 以上代码中,首先创建了一个ArrayList,并向其中添加了三个元素。然后创建与ArrayList大小相同的String数组。接下来,使用ArrayList的toArray()方法将其转换为Object数组。最后,使用Arrays.toString()方法将Object数组转换为String数组,并将其赋值给之前创建的String数组。最终,使用System.out.println()方法输出转换后的String数组。运行以上代码,输出为:[apple, banana, orange]。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值