并发问题老是感觉很棘手,这次碰到了一个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并发问题分析相关推荐

  1. Java集合Collection源码系列-ArrayList源码分析

    Java集合系列-ArrayList源码分析 文章目录 Java集合系列-ArrayList源码分析 前言 一.为什么想去分析ArrayList源码? 二.源码分析 1.宏观上分析List 2.方法汇 ...

  2. ArrayList 源码分析

    公众号原文:ArrayList 源码分析 博客原文:ArrayList 源码分析 以下源码分析使用的 Java 版本为 1.8 1. 概览 ArrayList 是基于数组实现的,继承 Abstract ...

  3. 【Java源码分析】Java8的ArrayList源码分析

    Java8的ArrayList源码分析 源码分析 ArrayList类的定义 字段属性 构造函数 trimToSize()函数 Capacity容量相关的函数,比如扩容 List大小和是否为空 con ...

  4. “并发冲突” 分析与解决

    并发冲突分析与解决      我们都知道,我们计算机中的运算都是交给CPU处理的,如果对于一个单核CPU来说,在绝对的某个时刻内,CPU只能同时完成一个任务,不可能同时的处理多个任务.但是我们都知道, ...

  5. ArrayList源码分析与手写

    本节主要分析JDK提供的ArrayList的源码,以及与自己手写的ArrayList进行对比. ArrayList源码分析 构造方法 private static final int DEFAULT_ ...

  6. MySQL不同隔离级别并发测试分析

    MySQL不同隔离级别并发测试分析 背景 事务 基于锁的并发控制 MVCC 测试方法 用例与分析 测试结果 用例分析 总结 背景 事务 事务是数据库执行过程中的一个逻辑单位,由一个有限的数据库操作序列 ...

  7. java集合框架02——ArrayList和源码分析

    上一章学习了Collection的架构,并阅读了部分源码,这一章开始,我们将对Collection的具体实现进行详细学习.首先学习List.而ArrayList又是List中最为常用的,因此本章先学习 ...

  8. Java中ArrayList源码分析

    一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...

  9. Java源码详解五:ArrayList源码分析--openjdk java 11源码

    文章目录 注释 类的继承与实现 构造函数 add操作 扩容函数 remove函数 subList函数 总结 本系列是Java详解,专栏地址:Java源码分析 ArrayList 官方文档:ArrayL ...

最新文章

  1. NVIDIA:关于深度学习Benchmark,英特尔错了
  2. android 如何去掉自定义标签页,Android中为TextView增加自定义的HTML标签
  3. 卷积神经网络(三):卷积神经网络CNN的简单实现(部分Python源码)
  4. ubuntu16安装go语言
  5. 【TSP】基于matlab蚁群算法求解旅行商问题【含Matlab源码 1130期】
  6. MT4API外汇跟单软件使用分享
  7. 如何用HTML和css实现拼图,怎样使用DIV+CSS实现拼图
  8. 2022-2028年中国酯基季铵盐行业市场全面调研及投资前景预测报告
  9. CSS实现背景图片透明文字不透明效果的两种方法
  10. html文本怎么转化为数字html,将阿拉伯数字转换为html文件中的阿拉伯/波斯数字...
  11. 免费通信时代何时真正到来?
  12. android矢量图之VectorDrawable ,自由又方便的填充色彩
  13. 淘宝店小蜜配置手册——店小蜜的配置框架
  14. LiteOS通信模组教程05-LiteOS的SAL及socket编程实例
  15. 深度学习机器学习理论知识:范数、稀疏与过拟合合集(5)Dropout原理,操作实现,为什么可以缓解过拟合,使用中的技巧
  16. EVP 签名和校验 Signing and Verifying
  17. 顺丰同城赴港IPO,或将成为第三方即时配送平台第一股
  18. 不支持php_fileinfo,如何打开php_fileinfo,如何支持php_fileinfo
  19. 什么是cool域名?
  20. 安全事件丨一心想做社交的支付宝,这下出了个“致命漏洞”

热门文章

  1. 求解求最大公约数定义的算法,这个程序求不出来,网上百度的算法不对?
  2. 吃鸡登录界面出现服务器正在维护该怎么办,吃鸡卡在登录页面进不去怎么办 | 手游网游页游攻略大全...
  3. 如何往linux虚拟机里传输文件
  4. 车载ECU嵌入式设备的诊断测试 – 读和写
  5. 怎样方便的在别人的PCB上修改,在你没有封装的情况下
  6. Linux系统中的文件系统格式区别及详解
  7. 声纹识别-2.GMM-UBM(高斯混合模型-通用背景模型)
  8. 对行列极大线性无关组交叉元素组成的矩阵可逆的一些思考
  9. 使用java画出宝马图标代码
  10. [UOJ500]任意基DFT