java.util.ArrayList#add探索
多线程操作
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探索相关推荐
- 一点一点看JDK源码(五)java.util.ArrayList 后篇之forEach
一点一点看JDK源码(五)java.util.ArrayList 后篇之forEach liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 代 ...
- 一点一点看JDK源码(四)java.util.ArrayList 中篇
一点一点看JDK源码(四)java.util.ArrayList 中篇 liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 在前篇中 ...
- Arrays.asList()返回的ArrayList,这是Arrays里内嵌的一个私有静态类,而并不是java.util.ArrayList类
测试代码: package array;import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; ...
- 一点一点看JDK源码(五)java.util.ArrayList 后篇之removeIf与Predicate
一点一点看JDK源码(五)java.util.ArrayList 后篇之removeIf与Predicate liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点 ...
- java.util.ArrayList
java.util.ArrayList 类定义 public class ArrayList<E> extends AbstractList<E> implements Lis ...
- 解决No converter for [class java.util.ArrayList] with preset Content-Type ‘null‘问题
文章目录 一.出现问题 二.解决方法 1.方法一: 2.方法二: 一.出现问题 二.解决方法 首先: 1.检查Maven依赖是否成功导入,记得clear后刷新! 2.更新lib目录,确保加入Maven ...
- JAVA.UTIL.ARRAYLIST 详解
[size=medium][color=red][b]java.util.ArrayList[/b][/color][/size] [size=medium] 数组和数组列表之间有着重大的区别.数组是 ...
- java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification
项目github地址:bitcarmanlee easy-algorithm-interview-and-practice 欢迎大家star,留言,一起学习进步 1.ConcurrentModific ...
- 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 ...
- 报错: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. ...
最新文章
- mysql repalication_mysql replication(主从复制)(一)MS模式
- awk: line 2: function strtonum never defined错误
- win7 磁盘根目录(E盘)添加管理员权限
- redis内部数据结构深入浅出
- Jquery的DOM
- java计算并显示学生的成绩_Java开学测试-学生成绩管理系统
- vagrant 常用命令
- POJ 3278 Catch That Cow
- SNMP原理及常用配置命令
- css - 布局 - rem布局
- 2022大厂高频面试题之CSS篇
- 电力设备巡检管理系统
- 安装系统或者进PE蓝屏 代码:IRQL NOT LESS OR EQUAL
- 快速注册认证小程序,三分钟学会免300元认证企业小程序
- 编写SQL语句,检索Customers表中所有的列,再编写另外的SELECT语句,仅检索顾客的ID
- 操作系统_生产者消费者问题
- 新形势下,企业如何做好数据安全治理?
- java服务器开发心得
- nginx过滤器模块
- android商城界面设计,Android购物商城界面设计