多线程操作 list.add(i); 后,与操作次数不符,并且报 ArrayIndexOutOfBoundsException 异常,

add 操作报异常……很是奇怪,进行对 list.add 进行探索, 异常示例见====> parallel(parallelStream)并发问题

首先进入源码进行查看

源码直接返回True,这操作…不太对吧,定眼一看,还真是……还不如直接给我来个void

/*** 将指定的元素追加到列表的末尾。 ** @param e 元素添加到此列表中* @return <tt>true</tt> (as specified by {@link Collection#add})*/
public boolean add(E e) {ensureCapacityInternal(size + 1);  // 增加空间数量!!elementData[size++] = e;return true;
}
进而进入 ensureCapacityInternal 方法进行查看
// 增加数组空间
private void ensureCapacityInternal(int minCapacity) {/** calculateCapacity(elementData, minCapacity) 计算真实需要的空间*        判断是否是自增长*           是:自动进行扩容, 容器数小于真实需要,返回真实需要量*           否:返回集合数量* ensureExplicitCapacity 保证有足够的空间进行存储【必要时进行扩容】*      真实用量大于集合容量*         进行扩容: grow(minCapacity);*/ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
grow(minCapacity) 方法

注意: Array数组最大容积为 Integer.MAX_VALUE - 8 有些虚拟机在数组中保留了一些标题字。尝试分配更大的阵列可能导致OutOfMemoryError:请求的阵列大小超过虚拟机限制

private void grow(int minCapacity) {// 原本集合大小int oldCapacity = elementData.length;//将集合大小增加为原来的一半 //oldCapacity >> 1 等价于oldCapacity/2, 但前者效率更高int newCapacity = oldCapacity + (oldCapacity >> 1);//增长后空间依然不足,将增长空间设置为空间大小if (newCapacity - minCapacity < 0)newCapacity = minCapacity;//增长空间大于Int最大值 Integer.MAX_VALUE - 8//因为溢出导致minCapacity < 0, 抛出OutOfMemoryError异常//否则为(minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// 拷贝到新扩容的数组中,minCapacity通常接近扩容后大小,尽可能利用空间,这是一个胜利:elementData = Arrays.copyOf(elementData, newCapacity);
}

IndexOutOfBoundsException问题

注意: 如果多线程运行会导致list.size()不一致,因为多个线程对一个ArrayList 进行操作,在达到扩容边缘的时候,多个线程同时对该集合进行增加

比如:容器大小为10,容器中此时有9个元素,并发线程为5

  • 线程1、2、3、4、5同时 add(),此时不扩容,就造成溢出

开始验证

在扩容的代码这里进行断点操作 int newCapacity = oldCapacity + (oldCapacity >> 1);

断点位置:java.util.ArrayList#add(E)

打印的:System.out.println(Thread.currentThread().getName()+"===put: "+ size + "====list.size: "+elementData.length);

执行如下测试代码
@Test
public void errorAdd() {//创建ArrayList集合List<Integer> listParallel = new ArrayList<>();//生成0-100000的数字  parallel多线程操作IntStream.range(0, 100000).parallel().forEach(i -> {//操作集合,其中会涉及到扩容,会出现问题listParallel.add(i);});
}

ForkJoinPool.commonPool-worker-3=put: 47list.size: 49
ForkJoinPool.commonPool-worker-5=put: 47list.size: 49
ForkJoinPool.commonPool-worker-2=put: 47list.size: 49
ForkJoinPool.commonPool-worker-1=put: 47list.size: 49
void
ForkJoinPool.commonPool-worker-4=put: 47list.size: 49
void
void
void
void
main=put: 4list.size: 10
void
ForkJoinPool.commonPool-worker-3=put: 52==list.size: 49

问题分析: 由上面日志可知:最后一条出现数组越界

报异常为:
java.lang.ArrayIndexOutOfBoundsExceptionat sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:423)at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:598)at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735)at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160)at java.util.stream.ForEachOps$ForEachOp$OfInt.evaluateParallel(ForEachOps.java:189)at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)at java.util.stream.IntPipeline.forEach(IntPipeline.java:404)at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:560)at self.studycode.bugs.StreamBug.errorAdd(StreamBug.java:47)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)at java.util.ArrayList.forEach(ArrayList.java:1257)at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)at java.util.ArrayList.forEach(ArrayList.java:1257)at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 10at java.util.ArrayList.add(ArrayList.java:463)at self.studycode.bugs.StreamBug.lambda$errorAdd$5(StreamBug.java:48)at java.util.stream.ForEachOps$ForEachOp$OfInt.accept(ForEachOps.java:205)at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)at java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:289)at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

丢失添加集合中值的问题

同样查看日志发现,日志中加粗的可以看到,main进程扩容后,其他进程也同时扩容,造成main进程扩容被回滚,因此进行添加的时候会造成值的丢失,如果此时main进程正添加元素,也会造成ArrayIndexOutOfBoundsException

main=put: 0==list.size: 10
void
main=put: 25==list.size: 28
void
main=put: 0==list.size: 10
ForkJoinPool.commonPool-worker-1=put: 0list.size: 10
ForkJoinPool.commonPool-worker-4=put: 0list.size: 10
ForkJoinPool.commonPool-worker-2=put: 0list.size: 10
ForkJoinPool.commonPool-worker-5=put: 0====list.size: 10

java.util.ArrayList#add探索相关推荐

  1. 一点一点看JDK源码(五)java.util.ArrayList 后篇之forEach

    一点一点看JDK源码(五)java.util.ArrayList 后篇之forEach liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 代 ...

  2. 一点一点看JDK源码(四)java.util.ArrayList 中篇

    一点一点看JDK源码(四)java.util.ArrayList 中篇 liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 在前篇中 ...

  3. Arrays.asList()返回的ArrayList,这是Arrays里内嵌的一个私有静态类,而并不是java.util.ArrayList类

    测试代码: package array;import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; ...

  4. 一点一点看JDK源码(五)java.util.ArrayList 后篇之removeIf与Predicate

    一点一点看JDK源码(五)java.util.ArrayList 后篇之removeIf与Predicate liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点 ...

  5. java.util.ArrayList

    java.util.ArrayList 类定义 public class ArrayList<E> extends AbstractList<E> implements Lis ...

  6. 解决No converter for [class java.util.ArrayList] with preset Content-Type ‘null‘问题

    文章目录 一.出现问题 二.解决方法 1.方法一: 2.方法二: 一.出现问题 二.解决方法 首先: 1.检查Maven依赖是否成功导入,记得clear后刷新! 2.更新lib目录,确保加入Maven ...

  7. JAVA.UTIL.ARRAYLIST 详解

    [size=medium][color=red][b]java.util.ArrayList[/b][/color][/size] [size=medium] 数组和数组列表之间有着重大的区别.数组是 ...

  8. java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification

    项目github地址:bitcarmanlee easy-algorithm-interview-and-practice 欢迎大家star,留言,一起学习进步 1.ConcurrentModific ...

  9. FAQ(80):java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification

    2018年8月31日 1.日志: 2018-04-13 20:00:55.757:WARN:oejs.ServletHandler:/g01-web/admin/activityManager/sen ...

  10. 报错:ON parse error: Cannot deserialize instance of `java.util.ArrayList<..> out of START_OBJECT

    JSON parse error: Cannot deserialize instance of java.util.ArrayList<com.sangfor.ngsoc.knowledge. ...

最新文章

  1. mysql repalication_mysql replication(主从复制)(一)MS模式
  2. awk: line 2: function strtonum never defined错误
  3. win7 磁盘根目录(E盘)添加管理员权限
  4. redis内部数据结构深入浅出
  5. Jquery的DOM
  6. java计算并显示学生的成绩_Java开学测试-学生成绩管理系统
  7. vagrant 常用命令
  8. POJ 3278 Catch That Cow
  9. SNMP原理及常用配置命令
  10. css - 布局 - rem布局
  11. 2022大厂高频面试题之CSS篇
  12. 电力设备巡检管理系统
  13. 安装系统或者进PE蓝屏 代码:IRQL NOT LESS OR EQUAL
  14. 快速注册认证小程序,三分钟学会免300元认证企业小程序
  15. 编写SQL语句,检索Customers表中所有的列,再编写另外的SELECT语句,仅检索顾客的ID
  16. 操作系统_生产者消费者问题
  17. 新形势下,企业如何做好数据安全治理?
  18. java服务器开发心得
  19. nginx过滤器模块
  20. android商城界面设计,Android购物商城界面设计

热门文章

  1. Altium Designer 在pcb下导入的原件引脚是绿的
  2. 日本惠普发表14.1型液晶内藏笔记本PC「dv4」系列2种模式
  3. 网管学习日记-MPLS-LDP协议配置
  4. HCIE-RS面试--STP弊端
  5. YANG-SUITE安装步骤
  6. 单臂路由VLAN通信
  7. zabbix详解(十四)——zabbix钉钉报警实战
  8. Linux之磁盘管理——磁盘分区
  9. 让java类继承TBase进行序列化
  10. Java 中时间处理SimpleDateFormat 中HH和hh的区别