以下环境是 JDK 1.8

ArrayList 的初始容量

面试官:你看过 ArrayList 的源码?

Python 小星:看过

面试官:那你说下ArrayList 的初始容量是多少?

Python 小星:10

面试官:你确定!?

......

1、ArrayList源码 -- 构造器

从源码里我们可以看到,无参构造函数,容量初始化为 0,有参构造函数的初始容量自定义。

我们也可以做个测试验证,我们通过反射获取 elementData 的长度,即是 ArrayList 的容量

输出结果:

思考哈:为什么默认长度是 10 ?

hashmap 里默认 16,是为了 hash 算法。@Python大星 认为固定长度的数组初始容量不需要考虑 hashmap 里的hash冲突,取 10 可能是不大不小的值,然后一直引用下来。就像你说为什么数组的下标都是从 0 开始,而不是从 1 开始,a [0] 就是偏移为 0 的位置。a [k] 就表示偏移 k 个元素类型大小的位置,少做一步减法,就一直被继承下来,无论是 C语言、Java语言 或者 Python 语言。

知道的小伙伴欢迎在评论下留言,也许无形中帮助了很多迷茫的人。

ArrayList 是“动态数组”-- 扩容

1、“动态”体现在 ArrayList的自动扩容上

ArrayList 如何完成一次扩容?

场景:ArrayList 初始容量是 10 ,如果再 add 一个元素,会怎样?

我们可以看到 JDK8 相比之前做了一点优化,使用了 >> 位运算

数组会按照 10 + 10 * 0.5 = 15 扩容(把原来的数组复制到另一个内存空间更大的数组中),扩容后再把指向原数的地址换到新数组。

ArrayList、LinkedList、Vector 的区别?

① Arraylist 和 Vector 是采用数组方式存储数据,所以插入数据慢,查找有下标,所以查询数据快

此数组元素数大于实际存储的数据以便增加插入元素,都允许直接序号索引元素,但是插入数据要涉及到数组元素移动等内存操作,

② Vector 本身所有方法都是用 synchronized 修饰的,线程安全,所以性能上比 ArrayList 要差

③ LinkedList 使用双向链表实现存储

按序号索引数据需要进行向前或向后遍历,查找较慢,但是插入数据时只需要记录本项前后项即可,插入数据较快。

为什么说 ArrayList 不是线程安全?

1、测试

输出结果:999

可以看出和我们预期的不一致。

在 add 操作分 2 步 :

① 判断 elementData 数组容量是否满足需求

② 在 elementData 对应位置上设置值

在多个线程进行 add 操作时可能会导致 elementData 数组越界。

elementData [size++] = e 设置值的操作同样会导致线程不安全。从这儿可以看出,这步操作也不是一个原子操作,线程不安全。

LinkedList

LinkedList 内部是双向链表结构

面试官:LinkedList 为什么说查找慢?它是怎么查找的?

Python 小星:因为它是链表结构,从表头开始遍历,所以当查找元素在链表后面,会比较慢

面试官:好的。回去等通知!

废话不多说,我们看下源码

从第二张图中我们可以看出:

链表中的 index 只是标记元素的相对于链表头部(first 指向的)node 的个数 ,这样在根据 index 查询时,可以根据 index 和 size 的关系,提高查询性能。当 index 大致在链表的前半部分时(index > 1)),从链表的首部开始遍历显然更快,而当 index 大致在链表的后半部分时(index > (size >> 1)),从链表的尾部开始遍历显然更快,这样就使得查找次数从 n 次将为了 n/2 次,虽然查找算法的时间复杂度还是 O (n)。

我们都知道 LinkedList 是链表结构,那到底是单向链表还是双向链表?

由上图可以看出Linkedlist是双向链表

为什么说 Vector 过时了,弃用了?

摘选 stackoverflow 的回答

https://stackoverflow.com/questions/1386275/why-is-java-vector-and-stack-class-considered-obsolete-or-deprecated#comment12234699_1386288

首先需要说明,在 Java 8 中 ,官方并没有弃用。

① Vector 对每个单独的方法进行同步;

② 通常 我们想要同步整个操作序列。

参考 https://javaconceptoftheday.com/not-use-vector-class-code/

① 无需 vector 也能实现线程安全

可以使用 Collections 类中 synchronizedList 来实现线程安全的 ArrayList

② 线程安全的 Vector 非常耗时

Vector 类的所有方法均已同步。这使 Vector 对象线程上的每个操作都安全。但是,这很耗时。因为,您需要为Vecto r在对象上执行的每个操作获取对象锁。通常,我们需要一组操作而不是每个操作都同步。一次锁定对象,为什么每次操作都要一次又一次次地获得锁?这是耗时的,降低性能。

③ Vector 设计不好

Vector 结合 2 个功能,“可调整大小的数组” 和 “同步”。这使设计不佳,而应始终使用ArrayList类。您将拥有可调整大小的数组,每当您要使其同步时,可以使用 Collections 中 synchronizedList 来实现线程安全的 ArrayList。

除了 Vector ,还有哪些线程安全的 ArrayList ?

synchronizedList 和 CopyOnWriteArrayList

1、synchronizedList

① synchronizedList 的用法(适合对数据要求较高的情况)

SynchronizedList 的 add 方法

add 方法

我们可以看出,SynchronizedList 用 synchronized 同步的是代码块,而 vector 用synchronized 同步的是方法。

【1】SynchronizedList 有很好的扩展和兼容功能。他可以将所有的 List 的子类转成线程安全的类;

【2】使用 SynchronizedList 的时候,进行遍历时要手动进行同步处理。

② CopyOnWriteArrayList (适合读多写少的场景)

1、add方法

CopyOnWriteArrayList 中 add 方法的实现(向 CopyOnWriteArrayList 里添加元素),可以发现在添加的时候是需要加锁的,写入时复制(CopyOnWrite),copy 一份新的数组进行相关的操作,在执行完修改操作后将原来集合指向新的集合来完成修改操作

add方法

2、get方法

读的时候不需要加锁,如果读的时候有多个线程正在向 CopyOnWriteArrayList 添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的 CopyOnWriteArrayList。

get方法

CopyOnWriteArrayList 缺点:

【1】 内存占有问题:很明显,两个数组同时驻扎在内存中,如果实际应用中,数据比较多,而且比较大的情况下,占用内存会比较大,针对这个其实可以用 ConcurrentHashMap 来代替。

【2】 数据一致性:CopyOnWrite 容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果你希望写入的的数据,马上能读到,请不要使用 CopyOnWrite 容器

@Python大星 | 文

如何把class里的vector结构体memcpy出来_面试官:请说出线程安全的 ArrayList 有哪些,除了Vector...相关推荐

  1. arraylist 后往前遍历_面试官:请说出线程安全的 ArrayList 有哪些,除了Vector

    以下环境是 JDK 1.8 ArrayList 的初始容量 面试官:你看过 ArrayList 的源码? Python 小星:看过 面试官:那你说下ArrayList 的初始容量是多少? Python ...

  2. 为什么线程池里的方法会执行两次_面试官问你java都有哪些线程池,自己是否自定义过线程池...

    我还记得大学实习面试时,被问到什么是线程池这个问题,因为这个题我被录取了,原因就是我背出来了,而另外一个面试的没背出来,说实话当时还真不知道它是干什么的,就是看面试题给背下来了,在之后就是在实际开发中 ...

  3. FATFS里的FIL结构体详解

    FATFS里的FIL结构体: FIL(file object 文件对象)掌控一个已打开的文件.由f_open()创建,由f_close()抛弃.应用程序除了可以修改结构里的cltbl,结构里的其他成员 ...

  4. vector 结构体排序_指下码上横戈行——排序

    常见的排序算法有冒泡排序,选择排序,堆排序,快速排序这几种,但十三写博客的目的是为了提高自己的编程解题能力,故在这里介绍如何能快速解决那些涉及到排序的编程问题,首先针对这些问题C++ STL库中已经有 ...

  5. vector 结构体类型 使用 排序

    如果要在Vector容器中存放结构体类型的变量,经常见到两种存放方式. 方式一:放入这个结构体类型变量的副本. 方式二:放入指向这个结构体类型变量的指针. 假设结构体类型变量是这样的, typedef ...

  6. 在Golang里如何实现结构体成员指针到结构体自身指针的转换

    原文地址:http://goworldgs.com/?p=37 在C语言中有一个经典的宏定义,可以将结构体struct内部的某个成员的指针转化为结构体自身的指针.下面是一个例子,通过FIELD_OFF ...

  7. lru算法C语言结构体指针,在Golang里如何实现结构体成员指针到结构体自身指针的转换...

    在C语言中有一个经典的宏定义,可以将结构体struct内部的某个成员的指针转化为结构体自身的指针.下面是一个例子,通过FIELD_OFFSET宏计算结构体内一个字段的偏移,函数getT可以从一个F*的 ...

  8. python 结构体数组 定义_一篇文章弄懂Python中所有数组数据类型

    前言 数组类型是各种编程语言中基本的数组结构了,本文来盘点下Python中各种"数组"类型的实现. list tuple array.array str bytes bytearr ...

  9. 结构体数组排列_学习RTOS(3)数据结构

    在 FreeRTOS 中存在着大量的基础数据结构列表和列表项的操作,列表和列表项是直接从 FreeRTOS 源码注释中的 list 和 list item 翻译过来的,其实就是对应我们 C 语言当中的 ...

最新文章

  1. PLS-00172: string literal too long
  2. POJ 1185 炮兵阵地 状压dp
  3. 【机器学习】决策树代码练习
  4. 最新综述:用于文本分类的数据增强方法
  5. Linux时间子系统之(十二):periodic tick
  6. React Native 加载多类型布局的实现——分类列表SectionList的封装
  7. 聊聊HystrixEventNotifier
  8. 2022年Python数据分析的宝藏地带
  9. python怎么制作图像_python数字图像处理(5):图像的绘制
  10. 页面滚动效果库,有点儿皮!
  11. Linux下main函数启动过程【程序员自我修养笔记】【自用】
  12. MacPE+WinPE-黑苹果之路
  13. oracle 01102 两实例,ORA 01102
  14. 深度学习自学(十三):Nas+Mnas移动端网络搜索结构
  15. dbvisualizer连接达梦_Dbvisualizer怎么使用,Dbvisualizer使用教程解析
  16. 使用NVIDIA端到端深度学习平台进行缺陷自动检测
  17. java在线反编译class文件工具地址
  18. 树莓派 kali系统默认密码
  19. 掌握搜索引擎优化方法使关键词快速排名
  20. 7月1日起交强险费率只与交通事故挂钩浮动

热门文章

  1. xenserver 虚拟机扩容lvm磁盘分区的方法_从零开始学Linux运维|35.LVM(逻辑卷管理)的创建...
  2. 夜间模式html,Web前端-夜间模式
  3. mysql视图_mysql之视图详解
  4. [javaweb] servlet处理请求参数中文乱码的问题
  5. android动态更改布局宽高,动态更改Android上的线性布局宽度或高度
  6. Python中读取文件中的json串,并将其写入到Excel表格中
  7. Python函数定义和函数调用
  8. 保留字(reserved field)是什么意思?
  9. C/C++ 为什么#ifndef 头文件 要用大写加下划线?(这就是一种约定俗成的规范)
  10. C语言进制转换时自动扩展位?(原码、反码、补码)(打印%o、%x时会自动扩展到32位【负数先得到其十进制真实数值,再根据其真实数值得到八进制、十进制补码】)