ArrayList源码超详细解析【不看会后悔系列】

一直在说ArrayList是非线程安全的,到底是为什么呢?

以ArrayList的add()方法为例,添加操作并不是一步完成,而是分为两步:

1.先在elementData[index]位置上添加一个新的元素

2.接着在为size进行+1操作。

描述:

如果此添加过程是在多线程的环境下,例如线程1已经完成了第一步将元素添加进了elementData[]中,但是此时的size并没有进行+1操作,而现在来了一个线程2,线程1的调度就结束了,size并没有+1,而线程2继续为elementData[]添加值,此时的size状态依然为之前的状态,接着由于线程1需要完成add()全过程,所以就发生了两次size++,此时添加的元素位置索引与size值就不匹配了。

所以这就是非线程安全。


一、ArrayList的继承结构

在解读源码之前我们需要对ArrayList的内部继承结构做了解:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
   

AbstractList:实现List接口操作规范,增、删、遍历等操作。
RandomAccess:提供随机访问功能
Cloneable:提供可拷贝功能
Serializable:提供可序列化功能

本文不对ArrayList成员变量及构造进行一一解析,ArrayList源码详细解析放在我的github上:

https://github.com/NolanJcn/Java-Is-Simple/tree/master/Source%20Code%20Analysis

欢迎star,后续将会陆续更新其他容器类源码解析!


想将ArrayList烂透与心中,以下几点必须掌握:

(1)扩容机制
(2)浅拷贝
(3)快速报错机制
(4)批量删除算法
(5)遍历方式

在我认为只要明白了以上几点,一千行ArrayList源码的阅读将能顺畅无比。

1.扩容机制

ArrayList源码中能需要扩容的无非就如下几类方法:add()、addAll()、readObject()。

扩容要从一个方法 ensureExplicitCapacity 讲起。

例如从 add(E e) 方法讲起:

//将指定的元素追加到此列表的末尾
public boolean add(E e) {
   
    //扩容
    ensureCapacityInternal(size + 1);
    elementData[size++] = e;
    return true;
}

方法很简单,先扩容,再维护 size 变量 ,接着往里填元素。
而添加方法中的扩容方法如下:

//中间过渡方法:确保要扩容的量为多少
private void ensureCapacityInternal(int minCapacity) {
   
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

此时可以发现方法中又调用了其他方法:继续跟踪

//确定了要扩容的量
private void ensureExplicitCapacity(int minCapacity) {
   
    modCount++;
    //如果需要扩容的量大于数组的长度
    
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值