ArrayList并发问题分析
并发问题老是感觉很棘手,这次碰到了一个ArrayList在线程池中add出现null数据的问题,虽然之前就知道ArrayList是非线程安全的,但是具体为啥不安全,为啥会出现空值,没有深入去理解,这次出现这个问题,经过自己分析,基本知道了这类问题出错会出在哪儿,对于这类问题的分析有点谱了
1.问题描述:
for循环线程池中启10个任务进行list.add(),加完后,发现第一个值为空,而且list的size也不是10
2.分析:
线程问题比较不好分析,主要是太抽象,都隐藏在后台,不能直观的观察到,而且时有时无,所以比较难分析
1.第一步,出这种问题,首先确定,肯定是共享变量,非原子化操作引起的
ArrayList的add方法很简单,就下面这两句
ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e;
第一句是扩容,可以排除(其实也有关系),直觉上应该是size++这个操作不是原子性的引起的
2.第二步,给自己插上想象的鸡翅膀
2.1 size小的原因,我猜如下:
最后的几个add,size++都在前一个线程没有加完的基础上++,导致最后的几个对象都加到最后一个位置上
(有待推敲,因为有扩容因素)
2.2 第一个为空的原因,我猜如下:
最开始的为空,第一个线程准备size++,第二个线程已经size++好了,导致两个线程都加到了第二个位置上,
第一个没人设置,所以为空(也不太确定,都走到size++,放置的时候size已经+2了,但为什么中间没有null的出现?)
好,分析完毕
可能是上面的原因,但是很多细节经不起推敲
比如这一步,如果是空的话,就会将size设置为默认值10,但是实际有size为9,或者8的情况
ensureCapacityInternal(size + 1); // Increments modCount!!
说明了什么?这一步没有执行,直接到1,然后用它的算法size=size+size>>1进行扩容,
其实不是没有执行是他自己有自定义的序列化方式,自己的size跟这个elementData的length无关
为什么没执行?就算再怎么乱序,也至少会有一个线程是从size=0开始执行的,只要是0就会默认将Arraylist copy进一个size为10的新list里
private void ensureCapacityInternal(int minCapacity) {if (elementData == EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//其中default_capacity为10,第一次执行的时候minCapacity为1,所以minCapacity为10}ensureExplicitCapacity(minCapacity); }
ensureExplicitCapacity这里执行的是下面的代码:如果新长度大于arr的长度,就grow他
if (minCapacity - elementData.length > 0)grow(minCapacity);
grow代码如下:拿到老size,将新size和老size的3/2进行比较,取大的将arr copy进去
int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0)newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity);
后来发现arraylist有自己的序列化逻辑,所以里面的arr通过fastjson的序列化方式打印出来可能不对,
size可能是错的,它里面的elementData是自定义的序列化,其实这段话没有意义,跟序列化无关
第一个值为空可能是因为两线程copy和赋值错序了,第一个线程size++=e了,第二个线程copy将空的赋进去,把第一个置空了,但为什么只有第一个为空?因为之后的至少都有值,不会有把空copy进arraylist里的情况
综上所述,加粗的两段话分别是arraylist在并发情况下size小和第一个为空的原因,也是我瞎猜的,但估计也差不多
总结如下:
1.线程并发问题,首要就分析共享变量
2.object对象的序列化方法很重要
3.写的太粗糙了,以后再改
ArrayList并发问题分析相关推荐
- Java集合Collection源码系列-ArrayList源码分析
Java集合系列-ArrayList源码分析 文章目录 Java集合系列-ArrayList源码分析 前言 一.为什么想去分析ArrayList源码? 二.源码分析 1.宏观上分析List 2.方法汇 ...
- ArrayList 源码分析
公众号原文:ArrayList 源码分析 博客原文:ArrayList 源码分析 以下源码分析使用的 Java 版本为 1.8 1. 概览 ArrayList 是基于数组实现的,继承 Abstract ...
- 【Java源码分析】Java8的ArrayList源码分析
Java8的ArrayList源码分析 源码分析 ArrayList类的定义 字段属性 构造函数 trimToSize()函数 Capacity容量相关的函数,比如扩容 List大小和是否为空 con ...
- “并发冲突” 分析与解决
并发冲突分析与解决 我们都知道,我们计算机中的运算都是交给CPU处理的,如果对于一个单核CPU来说,在绝对的某个时刻内,CPU只能同时完成一个任务,不可能同时的处理多个任务.但是我们都知道, ...
- ArrayList源码分析与手写
本节主要分析JDK提供的ArrayList的源码,以及与自己手写的ArrayList进行对比. ArrayList源码分析 构造方法 private static final int DEFAULT_ ...
- MySQL不同隔离级别并发测试分析
MySQL不同隔离级别并发测试分析 背景 事务 基于锁的并发控制 MVCC 测试方法 用例与分析 测试结果 用例分析 总结 背景 事务 事务是数据库执行过程中的一个逻辑单位,由一个有限的数据库操作序列 ...
- java集合框架02——ArrayList和源码分析
上一章学习了Collection的架构,并阅读了部分源码,这一章开始,我们将对Collection的具体实现进行详细学习.首先学习List.而ArrayList又是List中最为常用的,因此本章先学习 ...
- Java中ArrayList源码分析
一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...
- Java源码详解五:ArrayList源码分析--openjdk java 11源码
文章目录 注释 类的继承与实现 构造函数 add操作 扩容函数 remove函数 subList函数 总结 本系列是Java详解,专栏地址:Java源码分析 ArrayList 官方文档:ArrayL ...
最新文章
- NVIDIA:关于深度学习Benchmark,英特尔错了
- android 如何去掉自定义标签页,Android中为TextView增加自定义的HTML标签
- 卷积神经网络(三):卷积神经网络CNN的简单实现(部分Python源码)
- ubuntu16安装go语言
- 【TSP】基于matlab蚁群算法求解旅行商问题【含Matlab源码 1130期】
- MT4API外汇跟单软件使用分享
- 如何用HTML和css实现拼图,怎样使用DIV+CSS实现拼图
- 2022-2028年中国酯基季铵盐行业市场全面调研及投资前景预测报告
- CSS实现背景图片透明文字不透明效果的两种方法
- html文本怎么转化为数字html,将阿拉伯数字转换为html文件中的阿拉伯/波斯数字...
- 免费通信时代何时真正到来?
- android矢量图之VectorDrawable ,自由又方便的填充色彩
- 淘宝店小蜜配置手册——店小蜜的配置框架
- LiteOS通信模组教程05-LiteOS的SAL及socket编程实例
- 深度学习机器学习理论知识:范数、稀疏与过拟合合集(5)Dropout原理,操作实现,为什么可以缓解过拟合,使用中的技巧
- EVP 签名和校验 Signing and Verifying
- 顺丰同城赴港IPO,或将成为第三方即时配送平台第一股
- 不支持php_fileinfo,如何打开php_fileinfo,如何支持php_fileinfo
- 什么是cool域名?
- 安全事件丨一心想做社交的支付宝,这下出了个“致命漏洞”
热门文章
- 求解求最大公约数定义的算法,这个程序求不出来,网上百度的算法不对?
- 吃鸡登录界面出现服务器正在维护该怎么办,吃鸡卡在登录页面进不去怎么办 | 手游网游页游攻略大全...
- 如何往linux虚拟机里传输文件
- 车载ECU嵌入式设备的诊断测试 – 读和写
- 怎样方便的在别人的PCB上修改,在你没有封装的情况下
- Linux系统中的文件系统格式区别及详解
- 声纹识别-2.GMM-UBM(高斯混合模型-通用背景模型)
- 对行列极大线性无关组交叉元素组成的矩阵可逆的一些思考
- 使用java画出宝马图标代码
- [UOJ500]任意基DFT